Análisis exploratorio—completar titulo

Abril/2019

Índice

  1. Generalidades
  2. Entendimiento de los datos
  3. Análisis de Registros Pérdidos
  4. Análisis Exploratorio
    1. Análisis univariado - variables continuas
    2. Análisis univariado - variables cardinales
  5. Análisis de clasificación binaria usando WOE y el IV
  6. Modelo
    1. SMOTE - Balanceo de categoria minoritaria
    2. Análisis univariado - variables cardinales
  7. Relaciones entre variables
  8. Comparaciones

Haciendo click sobre cada una de las secciones puede ir directamente a cada una de ellas. Al finalizar cada sección encontrará un link para volver al índice.

Generalidades

El objetivo es desarrollar e implementar un modelo de predicción de rehospitalizaciones para apoyar los programas de evitabilidad post-hospitalaria. El análisis se realizará con información que describe las características sociodemográficas del individuo y con algunos datos recolectados por el personal hospitalario para un periodo de tiempo de dos años y medio, que va desde 2016 hasta 2018.

Volver al inicio

Entendimiento de los datos

El archivo contiene registros que corresponden a eventos de rehospitalizaciones y se encuentra detallado a nivel de cada evento hospitalario. En total son 34898 registros, 18 variables, descartando de manera inicial, aquellos atributos que se derivan después del segundo diagnóstico; los datos se describen a continuación:

# data_rehosp %>%
#   filter(rehosp_oms == 1) %>%
#   group_by(fecha_ingreso, ciudad) %>%
#   summarise(pago_hosp = sum(pago_hosp, na.rm = TRUE),
#             hosp = n()) %>%
#   plot_ly(data = .) %>%
#   add_trace(x = ~fecha_ingreso,
#             y = ~pago_hosp,
#             group = ~ciudad,
#             type = "scatter",
#             mode = "lines",
#             name = "Pago Hospitalización",
#             text = ~paste0("<b>Fecha Ingreso: </b>", fecha_ingreso, "<br><b>Pago Hospitalización: </b>", pago_hosp)) %>%

Generamos la estadística descriptiva de los datos; en ella se puede visualizar que es necesario realizar más adelante algunas conversiones en los tipos de datos que vienen por defecto (por ejemplo el estrato aparece como una variable numérica). Pero antes de continuar con la codificación, procederemos a realizar un breve análisis de valores pérdidos que nos permitan refinar la limpieza requerida en los datos.

Skim summary statistics
 n obs: 34897 
 n variables: 18 

-- Variable type:character -----------------------------------------------------
  variable missing complete     n min max empty n_unique
    ciudad       0    34897 34897   4  25     0      320
   diagnos     151    34746 34897   3   4     0     2974
 est_civil    9093    25804 34897   1   1     0        5
    genero       0    34897 34897   1   1     0        2
   ingreso   14194    20703 34897  13  21     0        4
 proveedor    3145    31752 34897   6  97     0      458

-- Variable type:numeric -------------------------------------------------------
   variable missing complete     n        mean          sd p0     p25     p50     p75      p100
  categoria     122    34775 34897     123.83        56.45  1      95     122     162       262
  dias_hosp       0    34897 34897       4.18         8.84  1       1       2       4       754
   dias_uce       0    34897 34897       0.021        0.51  0       0       0       0        63
   dias_uci       0    34897 34897       0.022        0.66  0       0       0       0        86
       edad       0    34897 34897      50.21        18.08 18      36      48      63       102
    estrato   10546    24351 34897       4.3          1.64 -1       3       5       6         6
     marcas       0    34897 34897       0.63         0.93  0       0       0       1         6
  pago_hosp       0    34897 34897 5706108.77  11447135.56  0 1184188 3019952 6175557 517393584
     quirur       0    34897 34897       0.49         0.5   0       0       0       1         1
       ramo       0    34897 34897      44.81        25.36 26      26      26      79        79
 rehosp_oms       0    34897 34897       0.022        0.15  0       0       0       0         1

-- Variable type:POSIXct -------------------------------------------------------
      variable missing complete     n        min        max     median n_unique
 fecha_ingreso       0    34897 34897 2015-12-01 2018-09-03 2017-04-18      939
require(scales)
Loading required package: scales
data_rehosp %>%
  filter(pago_hosp > 0) %>%
  group_by(fecha_ingreso) %>%
  summarise_all(~sum(pago_hosp)) %>%
  ggplot(aes(x=fecha_ingreso, y=pago_hosp)) +
  geom_line() + geom_smooth(method = "lm") + theme_minimal() +
  labs(title = "Pago Hosp en el tiempo",
         x= "Fecha_Ingreso",
         y = "Pago Hosp") +
    theme(plot.title = element_text(hjust = 0.5),
          legend.position = "none") + scale_y_continuous(labels = dollar) -> p

p <- ggplotly(p)

p

# p %>%
#   text = ~paste0("<b>Fecha Ingreso:<br></b>", fecha_ingreso,
#                  "<b>Fecha Ingreso:</b>", pago_hosp)
# ggplot(data_rehosp, aes(x = fecha_ingreso, y = rehosp_oms)) +
#   geom_line(aes(color = as.factor(rehosp_oms)), size = 1) +
#   scale_color_manual(values = c("#00AFBB", "#E7B800")) +
#   theme_minimal()
Volver al inicio

Análisis de Registros Pérdidos

En la gráfica siguiente podemos observar que hay en total 3 variables que no contienen registros vacios: estrato, estado civil e ingreso.

A nivel individual el porcentaje de valores perdidos para todos los casos es superior al 25%. De forma combinada hay 318 registros vacíos en ingreso, 259 en sólo el estrato y 144 en el estado civil, el resto de los campos nulos corresponde a combinaciones entre dos variables; por ende no podemos decir que la probabilidad de que falte un valor depende solo del valor observado, y usar un método para imputarlo (la forma no es aleatoria).

Para corroborar que los datos no faltan al azar, se realiza un grafico de correlación que nos ayude a verificar lo anterior. Para ello, construimos un dataframe que indique si el campo está vacio (1) o no (0); con esta información seleccionamos sólo aquellas columnas que tienen algunos (no todos) sus registros nulos y finalmente creamos la matrix de correlación.

Dado que con la anterior matrix a un nivel de significancia del 5% se comprueba la hipótesis inicial de no aleatoriedad, se procede a construir una tercera categoría para cada una de las variables que posee campos vacíos.

Para estimar si existe una asociación entre las variables que pueda derivarse en colinealidad, se procede primero a verificar que las variables no poseen una distribución normal, una vez realizado esto, se elige el test de Spearman para hallar la correlación lineal por atributo.

           statistic p.value
pago_hosp  0.3090747 0      
dias_uci   0.5090906 0      
dias_uce   0.5099995 0      
dias_hosp  0.3596024 0      
rehosp_oms 0.537792  0      

Los resultados confirman que ninguna de las variables pesenta una distribución normal y las correlaciones relacionadas a continuación, verifican posibles asociaciones entre las variables de los días en que el paciente estuvo internado en la Unidad de Cuidados Intensivos, en la Unidad de Cuidados Especiales y los días que el paciente estuvo hospitalizado. Por conocimiento de facto, la relación entre la variable “dias_uci” y “dias_uce” es entendible, ya que cuando un paciente que ha pasado por la Unidad de Cuidados Intensivos pasó su momento de crisis y su estado de salud es más estable, suele ser remitido a la Unidad de Cuidados Especiales.

Las correlaciones obtenidas no cumplen un umbral suficiente para considerarlas importantes, por ende se procede a conservarlas y evaluar más adelante si es preciso eliminarlas definitivamente al construir un modelo con fines predictivos. Por otro lado, la variable categoría y diagnóstico están altamente correlacionadas con la variable endógena, por lo que es necesario eliminarlas del análisis, para no incurrir en posibles sobreajustes en la etapa de modelado.

Teniendo en cuenta el análisis de datos perdidos o nulos, se decide descartar la variable ingreso ya que contiene mas de un 30% en datos perdidos.

Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   34897 obs. of  14 variables:
 $ edad      : Factor w/ 7 levels "18-30","31-40",..: 3 4 7 1 5 3 2 7 2 7 ...
 $ estrato   : Factor w/ 7 levels "1","2","3","4",..: 7 4 5 3 7 6 7 7 4 4 ...
 $ est_civil : Factor w/ 6 levels "C","D","S","Sin Informacion",..: 1 1 4 4 1 1 1 1 1 4 ...
 $ genero    : Factor w/ 2 levels "F","M": 1 2 1 1 2 1 2 2 1 1 ...
 $ marcas    : Factor w/ 3 levels "[0,2]","(2,4]",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ ramo      : Factor w/ 2 levels "26","79": 1 1 1 2 1 1 1 1 1 2 ...
 $ ciudad    : Factor w/ 320 levels "ABEJORRAL","ABREGO",..: 86 250 174 174 174 38 49 34 49 174 ...
 $ quirur    : Factor w/ 2 levels "No","Si": 2 2 2 1 1 2 2 2 1 2 ...
 $ dias_hosp : num  4 3 52 2 6 2 5 14 4 1 ...
 $ dias_uci  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ dias_uce  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ proveedor : Factor w/ 459 levels "ADMINISTRADORA CLINICA LA COLINA SAS",..: 192 247 33 201 33 105 116 230 81 139 ...
 $ pago_hosp : num  20604175 98000 2090823 1459979 246683 ...
 $ rehosp_oms: num  0 0 0 0 0 0 0 0 0 0 ...
Volver al inicio

Análisis Exploratorio

Análisis univariado - variables continuas

Es evidente la existencia también, de valores atípicos muy marcados tanto en el numéro de días de hospitalización, como en los números de días que el paciente estuvo en la Unidad de Cuidado Intensivo y Especial, en dónde los valores atípicos más grandes suceden en los eventos que terminaron en rehospitalización.

Con el análisis anterior no sólo se logra identificar variables con presencia de valores atípicos, sino que también es posible evidenciar que los datos se encuentran altamente desbalanceados. Por ende, antes de continur con la exploración de los datos se procede a tratar ambos problemas. En el caso de los outliers se truncará en los casos en que sea necesario, imputando los valores que superen cierto límite en el percntil, tanto mayor como menor.

data_rehosp %>%
  mutate(pago_hosp = ifelse(quirur == "Si" & rehosp_oms == 0, 
                            outlier(mydata = filter(data_rehosp, quirur == "Si" & rehosp_oms == 0), 
                                    value = "pago_hosp", q_min = 0, q_max = 0.97), pago_hosp),
         pago_hosp = ifelse(quirur == "Si" & rehosp_oms == 1, 
                            outlier(mydata = filter(data_rehosp, quirur == "Si" & rehosp_oms == 1),
                                    value = "pago_hosp", q_min = 0, q_max = 0.98), pago_hosp),
         pago_hosp = ifelse(quirur == "No" & rehosp_oms == 0, 
                            outlier(mydata = filter(data_rehosp, quirur == "No" & rehosp_oms == 0),                                                      value = "pago_hosp", q_min = 0, q_max = 0.97), pago_hosp), 
         pago_hosp = ifelse(quirur == "No" & rehosp_oms == 1, 
                            outlier(mydata = filter(data_rehosp, quirur == "No" & rehosp_oms == 1), 
                                    value = "pago_hosp", q_min = 0, q_max = 0.98), pago_hosp),
         dias_hosp = ifelse(rehosp_oms == 0, 
                            outlier(mydata = filter(data_rehosp, rehosp_oms == 0), 
                                                    value = "dias_hosp", q_min = 0, q_max = 0.99),
                            outlier(mydata = filter(data_rehosp, rehosp_oms == 1), 
                                                    value = "dias_hosp", q_min = 0, q_max = 0.99)),
         dias_uci = ifelse(rehosp_oms == 0, 
                           outlier(mydata = filter(data_rehosp, rehosp_oms == 0 & dias_uci > 0), 
                                                    value = "dias_uci", q_min = 0, q_max = 0.99)
                           , dias_uci),
         dias_uce = ifelse(rehosp_oms == 0, 
                           outlier(mydata = filter(data_rehosp, rehosp_oms == 0 & dias_uce > 0), 
                                                    value = "dias_uce", q_min = 0, q_max = 0.99)
                           , dias_uci)) -> data_rehosp

Se puede observar que tanto en el numéro de marcas como en la variable de pago, correspondiente al primer diagnóstico, no parece haber una diferencia significativa en la distribución al discriminar por la variable objetivo binaria, es decir, entre los casos de rehospitalización (1) y casos de no rehospitalización (0). Adicionalmente, la distibución en ambas variables no es simétrica. En el caso de las marcas se observa una asimetría positiva o sesgada a la derecha y de manera similar, aunque menos marcada, para el caso del pago en el primer diagnóstico.

Los datos se encuentran bastante dispersos y reflejan presencia de outliers.

Análisis univariado - variables cardinales

Observando las variables categóricas la diferencia entre la probabilidad de que el evento ocurra (haya rehospitalización) o no, se puede evidenciar sólo en algunas clases por categoría, pero en general, las proporciones suelen ser bastantes similares, por lo que no es posible elaborar a priori una hipótesis que estipule diferencias significativas en las distribuciones, por lo menos para ninguna de las dos variables relacionadas en el gráfico a continuación.

Por otro lado, el atributo que indica el hecho de que se hayan realizado procedimientos quirúrgicos durante la primera hospitalización muestran cierta diferencia en la distribuión por grupo; es más probable que la persona deba ser rehospitalizada de nuevo.

Con el objetivo de enriquecer el análisis exploratorio, se calcularán dos medidas muy comúnes de la teoría de la información, éstas permiten inferir algo del poder predictivo que pueden tener las variables independientes, antes de hacer parte de un modelo.

Volver al inicio

Análisis de clasificación binaria usando WOE y el IV

El peso de la evidencia (WOE) y el valor de la información (IV) ayudan, entre otras cosas, a determinar la contribución independiente de cada variable al resultado, y detectar relaciones lineales y no lineales. El WOE mide la relación entre la variable predictiva y el objeto binario, mientras que el IV mide la fuerza predictiva de esa relación.

La tabla a continuación contiene los valores del “valor de la información” con y sin el ajuste derivado de la validación cruzada. Cuando se realiza el ajuste con el objetivo de que los resultados sean más estables, sólo el pago del diagnóstico, si el paciente pasó por la Unidad de cuidados Especiales la primera vez y si fueron realizados procedimientos quirúrgicos serán las únicas variables con suficiente capacidad de predicción a nivel individual y univariable (Iv > 5%). Cuando se relaja el supuesto, IV sin restar el penalty, se incluirían las marcas y la edad y la ciudad.

Variable IV PENALTY AdjIV
11 dias_uce 3.1518843 0.3928314 2.7590529
10 dias_uci 3.1087170 0.5675834 2.5411335
13 pago_hosp 0.6371062 0.0981920 0.5389142
8 quirur 0.2797708 0.0260082 0.2537626
12 proveedor 0.3125381 0.2372478 0.0752903
9 dias_hosp 0.0650132 0.0371076 0.0279056
3 est_civil 0.0138697 0.0100274 0.0038423
6 ramo 0.0011560 0.0000293 0.0011268
4 genero 0.0132468 0.0136942 -0.0004474
5 marcas 0.0056888 0.0080270 -0.0023382
1 edad 0.0191404 0.0224028 -0.0032624
2 estrato 0.0201715 0.0297575 -0.0095859
7 ciudad 0.1671995 0.1823239 -0.0151244

De acuerdo al poder predictivo de cada una de las variables, se eligen aquellas cuyo Valor de la informaciÓn (IV) sea superior al 2% (0,02). Las variables con IV inferiores a este valor se consideran impredictivas y se decide descartarlas. Las variables que continuan, en orden de relevancia segun su poder predictor, son:

Enfocandonos en el pago del diagnóstico, el cual, es la variable con mayor influencia, el WOE nos indica una relación no lineal, con un incremento en el WOE a medida que disminuye el rango de pago en el diagnóstico.

edad N Percent WOE IV PENALTY
18-30 3543 0.1450385 -0.2882992 0.0105342 0.0086966
31-40 5236 0.2143442 0.0205769 0.0106259 0.0094036
41-50 4393 0.1798346 -0.1163345 0.0129293 0.0106795
51-60 4141 0.1695186 0.0807751 0.0140790 0.0160969
61-70 3280 0.1342721 0.1008028 0.0155110 0.0193519
71-80 2228 0.0912068 0.0997494 0.0164630 0.0199446
81+ 1607 0.0657852 0.1925815 0.0191404 0.0224028

Como se pudo observar en el analisis del WOE, esta técnica ajusta los valores de las variables numericas en rangos acotados de acuerdo al valor de la informacion de cada una de ellas en relacion con la variable dependiente. Por esto, es importante transformar dichas variables en los rangos recomendados.

# data_rehosp %>%
#   mutate(pago_hosp1 = case_when( pago_hosp <= 107410 ~ "[0,107410]",
#                            pago_hosp >= 107570 & pago_hosp <= 776965 ~ "[107570,776965]",
#                            pago_hosp >= 777697 & pago_hosp <= 1547806 ~ "[777697,1547806]",
#                            pago_hosp >= 1547847 & pago_hosp <= 2251764 ~ "[1547847,2251764]",
#                            pago_hosp >= 2251913 & pago_hosp <= 3021862 ~ "[2251913,3021862]",
#                            pago_hosp >= 3022030 & pago_hosp <= 3996928 ~ "[3022030,3996928]",
#                            pago_hosp >= 3996933 & pago_hosp <= 5328423 ~ "[3996933,5328423]",
#                            pago_hosp >= 5329500 & pago_hosp <= 7048290 ~ "[5329500,7048290]",
#                            pago_hosp >= 7048902 & pago_hosp <= 11408415 ~ "[7048902,11408415]",
#                            pago_hosp >= 11408625 & pago_hosp <= 47387883 ~ "[11408625,47387883]",
#                            pago_hosp >= 47387883 ~ "[47387883+"),
#          dias_hosp1 = case_when( dias_hosp = 1 ~ "[1]",
#                                 dias_hosp = 2 ~ "[2]",
#                                 dias_hosp = 3 ~ "[3]",
#                                 dias_hosp = 4 ~ "[4]",
#                                 dias_hosp >= 5 & dias_hosp <= 7 ~ "[5,7]",
#                                 dias_hosp >= 8 & dias_hosp <= 30 ~ "[8,30]")) -> data_rehosp2
# 
# 
# str(data_rehosp)
Volver al inicio

Modelo

Seleccion de variables para el modelo

data_rehosp %>%
  select(id,
        pago_hosp,
        quirur,
        dias_uce,
        dias_uci,
        proveedor,
        dias_hosp,
        estrato,
        ciudad,
        rehosp_oms) -> data_rehosp

data_rehosp %>%
  sample_frac(size = 0.7) -> training

data_rehosp %>%
  anti_join(x = .,
            y = training,
            by = "id") -> testing

testing %>%
  select(-id) -> testing

training %>%
  select(-id) %>%
  mutate(rehosp_oms = as.factor(rehosp_oms)) -> training

SMOTE

Como se habia mencionado anteriormente, la informacion se encuentra desbalanceada; esto es, teniendo en cuenta que el problema en que se esta trabajando consiste en la clasificacion de una variable binaria, se debe analizar el nivel de representacion de los posibles valores de la variable binaria dentro del conjunto de informacion.

#verificar clase balanceada
prop.table(table(data_rehosp$rehosp_oms))

         0          1 
0.97750523 0.02249477 

Vemos que la representacion para la categoría positiva es un poco mas del 2% de la información. En este caso vamos a realizar un tratamiento de la información que permita aumentar la clase minoritaria, sin utilizar soluciones genéricas como reducir la clase mayoritaria al nivel de la clase minoritaria.

Para este caso vamos a utilizar la técnica SMOTE (Synthetic Minority Oversampling Method), la cual genera nuevas instancias artificiales de la clase minoritaria interpolando los valores de las instancias minoritarias más cercanas a una dada.

Por medio de SMOTE se generará un nuevo set de datos de entrenamiento, en el cual se tenga un 60% de informacion para la categoria negativa (rehosp_oms = 0) y 40% para la categoria positiva (rehosp_oms = 0).

training <- SMOTE(rehosp_oms ~ ., as.data.frame(training), perc.over = 300, perc.under = 200)

Verificamos que el set de entrenamiento se encuentre balanceado

prop.table(table(training$rehosp_oms))

  0   1 
0.6 0.4 

Estimando el modelo

mylogit <- glm(rehosp_oms ~ pago_hosp + quirur +  dias_hosp + estrato, data = training, family = "binomial")

summary(mylogit)

Call:
glm(formula = rehosp_oms ~ pago_hosp + quirur + dias_hosp + estrato, 
    family = "binomial", data = training)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.3461  -1.0437  -0.7025   1.1568   3.4056  

Coefficients:
                             Estimate     Std. Error z value             Pr(>|z|)    
(Intercept)            -0.33954298001  0.29320309125  -1.158               0.2468    
pago_hosp              -0.00000017310  0.00000000997 -17.363 < 0.0000000000000002 ***
quirurSi               -0.01886062365  0.05890128561  -0.320               0.7488    
dias_hosp              -0.03275835940  0.00839218488  -3.903            0.0000948 ***
estrato2                0.37228682090  0.32070176606   1.161               0.2457    
estrato3                0.36200991618  0.30201394807   1.199               0.2307    
estrato4                0.69663076482  0.29901937446   2.330               0.0198 *  
estrato5                0.76055048992  0.29772130521   2.555               0.0106 *  
estrato6                0.49688051860  0.29632474547   1.677               0.0936 .  
estratoSin Informacion  0.58929455937  0.29363290100   2.007               0.0448 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 7457.0  on 5539  degrees of freedom
Residual deviance: 6966.4  on 5530  degrees of freedom
AIC: 6986.4

Number of Fisher Scoring iterations: 4
pred <- predict(mylogit, newdata = training[-9], type = "response")
 
y_pred_num_train <- ifelse(pred > 0.5, 1, 0)
y_pred_train <- factor(y_pred_num, levels=c(0, 1))
y_act_train <- training$rehosp_oms
 
mean(y_pred_train == y_act_train)  
longer object length is not a multiple of shorter object lengthlonger object length is not a multiple of shorter object length
[1] 0.6541217

Prediciendo y evaluando performance

prob_pred = predict(mylogit, type = 'response', newdata = testing[-9])
y_pred = ifelse(prob_pred > 0.5, 1, 0)
y_pred_fac <- factor(y_pred, levels=c(0, 1))
y_act <- testing$rehosp_oms
 
mean(y_pred == y_act)  # X%
[1] 0.8147865
 

library(ROCR)
ROCRpred = prediction(prob_pred, testing$rehosp_oms)
 
# Performance function
ROCRperf = performance(ROCRpred, "tpr", "fpr")

perf1 <- performance(ROCRpred, "prec", "rec")
plot(perf1)

 
# Plot ROC curve
plot(ROCRperf)

# Add colors
plot(ROCRperf, colorize=TRUE)

# Add threshold labels 
plot(ROCRperf, colorize=TRUE, print.cutoffs.at=seq(0,1,by=0.1), text.adj=c(-0.2,1.7))



prob_pred = predict(mylogit, type = 'response', newdata = testing[-9])
y_pred = ifelse(prob_pred > 0.5, 1, 0)
cm = table(as.matrix(testing[, 9]), y_pred > 0.5)

length(y_pred)
[1] 10469
LS0tDQp0aXRsZTogIjxjZW50ZXI+PGJyPk1vZGVsbyBQcmVkaWNjacOzbiBkZSBSZWhvc3BpdGFsaXphY2lvbmVzPC9icj4iDQpEYXRlOiAiPGNlbnRlcj5BYnJpbC8yMDE5PC9jZW50ZXI+Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KPGgxIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48YSBpZD0iSW5pY2lvIj48L2E+QW7DoWxpc2lzIGV4cGxvcmF0b3Jpby0tLWNvbXBsZXRhciB0aXR1bG88L2gxPg0KPGg0IHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij5BYnJpbC8yMDE5PC9oND4NCg0KPHRhYmxlPg0KPHRyPg0KPHRkPjxpbWcgc3R5bGU9IndpZHRoOjI3MHB4OyBoZWlnaHQ6MjAwcHg7IiBzcmM9IlNVUkEucG5nIiAvPjwvdGQ+DQo8dGQ+PGltZyBzdHlsZT0id2lkdGg6NTUwcHg7IGhlaWdodDoxMjBweDsiIHNyYz0iRGF0YWx5dGljcy5wbmciIC8+PC90ZD4NCjwvdHI+DQo8L3RhYmxlPg0KDQoNCjxoMiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+w41uZGljZTwvaDI+DQo8b2w+DQogICAgPGxpPjxhIGhyZWY9IiNHZW5lcmFsaWRhZGVzIj5HZW5lcmFsaWRhZGVzPC9hPjwvbGk+DQogICAgPGxpPjxhIGhyZWY9IiNFbnRlbmRpbWllbnRvIj5FbnRlbmRpbWllbnRvIGRlIGxvcyBkYXRvczwvYT48L2xpPg0KICAgIDxsaT48YSBocmVmPSIjUGVyZGlkb3MiPkFuw6FsaXNpcyBkZSBSZWdpc3Ryb3MgUMOpcmRpZG9zPC9hPjwvbGk+DQogICAgPGxpPjxhIGhyZWY9IiNBbmFsaXNpcyI+QW7DoWxpc2lzIEV4cGxvcmF0b3JpbzwvYT48L2xpPg0KICAgICAgPG9sPg0KICAgICAgICA8bGk+PGEgaHJlZj0iI0FuYWxpc2lzQ29uIj5BbsOhbGlzaXMgdW5pdmFyaWFkbyAtIHZhcmlhYmxlcyBjb250aW51YXM8L2E+PC9saT4NCiAgICAgICAgPGxpPjxhIGhyZWY9IiNBbmFsaXNpc0NhciI+QW7DoWxpc2lzIHVuaXZhcmlhZG8gLSB2YXJpYWJsZXMgY2FyZGluYWxlczwvYT48L2xpPg0KICAgICAgPC9vbD4NCiAgICA8bGk+PGEgaHJlZj0iI0FuYWxpc2lzV09FIj5BbsOhbGlzaXMgZGUgY2xhc2lmaWNhY2nDs24gYmluYXJpYSB1c2FuZG8gV09FIHkgZWwgSVY8L2E+PC9saT4NCiAgICA8bGk+PGEgaHJlZj0iI01vZGVsbyI+TW9kZWxvPC9hPjwvbGk+DQogICAgICA8b2w+DQogICAgICAgIDxsaT48YSBocmVmPSIjU01PVEUiPlNNT1RFIC0gQmFsYW5jZW8gZGUgY2F0ZWdvcmlhIG1pbm9yaXRhcmlhPC9hPjwvbGk+DQogICAgICAgIDxsaT48YSBocmVmPSIjQW5hbGlzaXNDYXIiPkFuw6FsaXNpcyB1bml2YXJpYWRvIC0gdmFyaWFibGVzIGNhcmRpbmFsZXM8L2E+PC9saT4NCiAgICAgIDwvb2w+DQogICAgPGxpPjxhIGhyZWY9IiNSZWxhY2lvbmVzIj5SZWxhY2lvbmVzIGVudHJlIHZhcmlhYmxlczwvYT48L2xpPg0KICAgIDxsaT48YSBocmVmPSIjQ29tcGFyYWNpb25lcyI+Q29tcGFyYWNpb25lczwvYT48L2xpPg0KPC9vbD4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+SGFjaWVuZG8gY2xpY2sgc29icmUgY2FkYSB1bmEgZGUgbGFzIHNlY2Npb25lcyBwdWVkZSBpciBkaXJlY3RhbWVudGUgYSBjYWRhIHVuYSBkZSBlbGxhcy4gQWwgZmluYWxpemFyIGNhZGEgc2VjY2nDs24gZW5jb250cmFyw6EgdW4gbGluayBwYXJhIHZvbHZlciBhbCDDrW5kaWNlLjwvcD4NCg0KPGgyIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48YSBpZD0iR2VuZXJhbGlkYWRlcyI+R2VuZXJhbGlkYWRlczwvYT48L2gyPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5FbCBvYmpldGl2byBlcyBkZXNhcnJvbGxhciBlIGltcGxlbWVudGFyIHVuIG1vZGVsbyBkZSBwcmVkaWNjacOzbiBkZSByZWhvc3BpdGFsaXphY2lvbmVzIHBhcmEgYXBveWFyIGxvcyBwcm9ncmFtYXMgZGUgZXZpdGFiaWxpZGFkIHBvc3QtaG9zcGl0YWxhcmlhLiBFbCBhbsOhbGlzaXMgc2UgcmVhbGl6YXLDoSBjb24gaW5mb3JtYWNpw7NuIHF1ZSBkZXNjcmliZSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBzb2Npb2RlbW9ncsOhZmljYXMgZGVsIGluZGl2aWR1byB5IGNvbiBhbGd1bm9zIGRhdG9zIHJlY29sZWN0YWRvcyBwb3IgZWwgcGVyc29uYWwgaG9zcGl0YWxhcmlvIHBhcmEgdW4gcGVyaW9kbyBkZSB0aWVtcG8gZGUgZG9zIGHDsW9zIHkgbWVkaW8sIHF1ZSB2YSBkZXNkZSAyMDE2IGhhc3RhIDIwMTguPC9wPg0KDQoNCjxhIGhyZWY9IiNJbmljaW8iPlZvbHZlciBhbCBpbmljaW88L2E+PC9saT4NCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBlY2hvID0gRkFMU0UsIGV2YWwgPVRSVUV9DQpzZXQuc2VlZCgxMjM0KQ0Kb3B0aW9ucyhzY2lwZW4gPSAxMDApDQpybShsaXN0ID0gbHMoKSkNCnNvdXJjZSgiZnVuY3Rpb25zX3Bsb3QuUiIpDQoNCmxpc3Qub2YucGFja2FnZXMgPC0gYygicmVhZHhsIiwgImRwbHlyIiwgImdncGxvdDIiLCAiZ2djb3JycGxvdCIsICJWSU0iLCAiUkNvbG9yQnJld2VyIiwgIkluZm9ybWF0aW9uIiwgImtuaXRyIiwgImthYmxlRXh0cmEiLCAiZ3JpZEV4dHJhIiwgInNraW1yIiwgIm5vcnRlc3QiLCAiR0dhbGx5IiwgInBsb3RseSIsICJsYXR0aWNlIiwgIkRNd1IiLCAiY2FUb29scyIsICJwbG90bHkiKQ0KDQpuZXcucGFja2FnZXMgPC0gbGlzdC5vZi5wYWNrYWdlc1shKGxpc3Qub2YucGFja2FnZXMgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKVssIlBhY2thZ2UiXSldDQppZihsZW5ndGgobmV3LnBhY2thZ2VzKSkgaW5zdGFsbC5wYWNrYWdlcyhuZXcucGFja2FnZXMpDQoNCmxvYWQgPC0gbGFwcGx5KGxpc3Qub2YucGFja2FnZXMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCmBgYA0KDQo8aDIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxhIGlkPSJFbnRlbmRpbWllbnRvIj5FbnRlbmRpbWllbnRvIGRlIGxvcyBkYXRvczwvYT48L2gyPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkVsIGFyY2hpdm8gY29udGllbmUgcmVnaXN0cm9zIHF1ZSBjb3JyZXNwb25kZW4gYSBldmVudG9zIGRlIHJlaG9zcGl0YWxpemFjaW9uZXMgeSBzZSBlbmN1ZW50cmEgZGV0YWxsYWRvIGEgbml2ZWwgZGUgY2FkYSBldmVudG8gaG9zcGl0YWxhcmlvLiBFbiB0b3RhbCBzb24gMzQ4OTggcmVnaXN0cm9zLCAxOCB2YXJpYWJsZXMsIGRlc2NhcnRhbmRvIGRlIG1hbmVyYSBpbmljaWFsLCBhcXVlbGxvcyBhdHJpYnV0b3MgcXVlIHNlIGRlcml2YW4gZGVzcHXDqXMgZGVsIHNlZ3VuZG8gZGlhZ27Ds3N0aWNvOyBsb3MgZGF0b3Mgc2UgZGVzY3JpYmVuIGEgY29udGludWFjacOzbjo8L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0KZGF0YV9yZWhvc3AgPC0gcmVhZF94bHN4KCJEQVRBX1JFSE9TUC54bHN4IixuYSA9IGMoIm5hIiwgIk5BIiwgIm51bGwiLCAiTlVMTCIpKQ0KZGF0YV9yZWhvc3AgJT4lDQogIHNlbGVjdChFZGFkX0hvc3BpdGFsaXphY2lvbiwNCiAgICAgICAgIEVzdHJhdG9fVml2aWVuZGEsDQogICAgICAgICBSYW5nb19JbmdyZXNvc19EZXNjLA0KICAgICAgICAgRXN0YWRvX0NpdmlsLA0KICAgICAgICAgR2VuZXJvLA0KICAgICAgICAgY2FudGlkYWRfbWFyY2FzLA0KICAgICAgICAgUmFtb19JZCwNCiAgICAgICAgIENpdWRhZF9Db250YWN0b19Ob21icmUsDQogICAgICAgICBDb2RpZ29fRGlhZ25vc3RpY29fT3AsDQogICAgICAgICBDYXRlZ29yaWFfRHhfSWQsDQogICAgICAgICBRdWlydXJnaWNvLA0KICAgICAgICAgRmVjaGFfSW5ncmVzb19Ib3NwLA0KICAgICAgICAgTnVtZXJvX0RpYXNfSG9zcGl0YWxhcmlvLA0KICAgICAgICAgTnVtZXJvX0RpYXNfVWNpLA0KICAgICAgICAgTnVtZXJvX0RpYXNfVWNlLA0KICAgICAgICAgUHJvdmVlZG9yLA0KICAgICAgICAgVmFsb3JfUGFnYWRvX0RpYWdub3N0aWNvLA0KICAgICAgICAgcmVob3NwX2NhdF9vbXMpICU+JQ0KICByZW5hbWUoZWRhZCA9IEVkYWRfSG9zcGl0YWxpemFjaW9uLCANCiAgICAgICAgIGVzdHJhdG8gPSBFc3RyYXRvX1ZpdmllbmRhLA0KICAgICAgICAgaW5ncmVzbyA9IFJhbmdvX0luZ3Jlc29zX0Rlc2MsDQogICAgICAgICBlc3RfY2l2aWwgPSBFc3RhZG9fQ2l2aWwsDQogICAgICAgICBnZW5lcm8gPSBHZW5lcm8sDQogICAgICAgICBtYXJjYXMgPSBjYW50aWRhZF9tYXJjYXMsDQogICAgICAgICByYW1vID0gUmFtb19JZCwNCiAgICAgICAgIGNpdWRhZCA9IENpdWRhZF9Db250YWN0b19Ob21icmUsDQogICAgICAgICBkaWFnbm9zID0gQ29kaWdvX0RpYWdub3N0aWNvX09wLA0KICAgICAgICAgY2F0ZWdvcmlhID0gQ2F0ZWdvcmlhX0R4X0lkLA0KICAgICAgICAgcXVpcnVyID0gUXVpcnVyZ2ljbywNCiAgICAgICAgIGZlY2hhX2luZ3Jlc28gPSBGZWNoYV9JbmdyZXNvX0hvc3AsDQogICAgICAgICBkaWFzX2hvc3AgPSBOdW1lcm9fRGlhc19Ib3NwaXRhbGFyaW8sDQogICAgICAgICBkaWFzX3VjaSA9IE51bWVyb19EaWFzX1VjaSwNCiAgICAgICAgIGRpYXNfdWNlID0gTnVtZXJvX0RpYXNfVWNlLA0KICAgICAgICAgcHJvdmVlZG9yID0gUHJvdmVlZG9yLA0KICAgICAgICAgcGFnb19ob3NwID0gVmFsb3JfUGFnYWRvX0RpYWdub3N0aWNvLA0KICAgICAgICAgcmVob3NwX29tcyA9IHJlaG9zcF9jYXRfb21zKSAtPiBkYXRhX3JlaG9zcA0KaGVhZChkYXRhX3JlaG9zcCkNCmBgYA0KDQpgYGB7cn0NCiMgZGF0YV9yZWhvc3AgJT4lDQojICAgZmlsdGVyKHJlaG9zcF9vbXMgPT0gMSkgJT4lDQojICAgZ3JvdXBfYnkoZmVjaGFfaW5ncmVzbywgY2l1ZGFkKSAlPiUNCiMgICBzdW1tYXJpc2UocGFnb19ob3NwID0gc3VtKHBhZ29faG9zcCwgbmEucm0gPSBUUlVFKSwNCiMgICAgICAgICAgICAgaG9zcCA9IG4oKSkgJT4lDQojICAgcGxvdF9seShkYXRhID0gLikgJT4lDQojICAgYWRkX3RyYWNlKHggPSB+ZmVjaGFfaW5ncmVzbywNCiMgICAgICAgICAgICAgeSA9IH5wYWdvX2hvc3AsDQojICAgICAgICAgICAgIGdyb3VwID0gfmNpdWRhZCwNCiMgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwNCiMgICAgICAgICAgICAgbW9kZSA9ICJsaW5lcyIsDQojICAgICAgICAgICAgIG5hbWUgPSAiUGFnbyBIb3NwaXRhbGl6YWNpw7NuIiwNCiMgICAgICAgICAgICAgdGV4dCA9IH5wYXN0ZTAoIjxiPkZlY2hhIEluZ3Jlc286IDwvYj4iLCBmZWNoYV9pbmdyZXNvLCAiPGJyPjxiPlBhZ28gSG9zcGl0YWxpemFjacOzbjogPC9iPiIsIHBhZ29faG9zcCkpICU+JQ0KYGBgDQoNCg0KPHVsPg0KPGxpPlZhcmlhYmxlcyBjb250aW51YXMgKDQpDQo8dWw+DQo8bGk+ZGlhc19ob3NwOiBEw61hcyBkZSBob3NwaXRhbGl6YWNpw7NuPC9saT4NCjxsaT5kaWFzX3VjaTogTsO6bWVybyBkw61hcyBlbiBVQ0k8L2xpPg0KPGxpPmRpYXNfdWNlOiBOw7ptZXJvIGTDrWFzIGVuIFVDRTwvbGk+DQo8bGk+cGFnb19ob3NwOiBWYWxvciBwYWdhZG8gcHJpbWVyYSBob3NwaXRhbGl6YWNpw7NuPC9saT4NCjwvdWw+DQo8L2xpPg0KPC91bD4NCjx1bD4NCjxsaT5WYXJpYWJsZXMgbm9taW5hbGVzICg1KQ0KPHVsPg0KPGxpPmVzdHJhdG86IEVzdHJhdG8gVml2aWVuZGEgKDAsMSwyLDMsNCw1LDYsLTEpPC9saT4NCjxsaT5lc3RfY2l2aWw6IEVzdGFkbyBjaXZpbCAoQyxELFMsVSxWLC0xKTwvbGk+DQo8bGk+Y2l1ZGFkOiBDaXVkYWQgZGUgY29udGFjdG8gZGVsIGFzZWd1cmFkbzwvbGk+DQo8bGk+ZGlhZ25vczogQ8OzZGlnbyBkaWFnbsOzc3RpY28gQ0lFMTAgZGUgbGEgcHJpbWVyYSBhdGVuY2nDs24gPC9saT4NCjxsaT5jYXRlZ29yaWE6IENhdGVnb3LDrWEgZGVsIGRpYWduw7NzdGljbyBzZWfDum4gZWwgdGlwbyBkZSBlbmZlcm1lZGFkPC9saT4NCjwvdWw+DQo8L2xpPg0KPC91bD4NCjx1bD4NCjxsaT5WYXJpYWJsZSBkaWNvdMOzbWljYSAoNCkNCjx1bD4NCjxsaT5nZW5lcm86IEfDqW5lcm8gZGVsIGFzZWd1cmFkbyAoTSxGKTwvbGk+DQo8bGk+cmFtbzogUmFtbyBhbCBxdWUgcGVydGVuZWNlIGVsIGFzZWd1cmFkbzwvbGk+DQo8bGk+cXVpcnVyOiBTaSB0dXZvIGFsZ3VuIHRpcG8gZGUgc2VydmljaW8gcmVsYWNpb25hZG8gYSBwcm9jZWRpbWllbnRvIHF1aXLDunJnaWNvPC9saT4NCjxsaT5yZWhvc3BfY2F0X29tczogU2ltaWxpdHVkIGNhdGVnb3LDrWEgY2llMTAuIEVzdGEgZXMgbnVlc3RyYSB2YXJpYWJsZSBvYmpldGl2byA8L2xpPg0KPC91bD4NCjwvbGk+DQo8L3VsPg0KPHVsPg0KPGxpPlZhcmlhYmxlcyBkaXNjcmV0YXMgKDIpDQo8dWw+DQo8bGk+ZWRhZDogRWRhZCBkZWwgYXNlZ3VyYWRvIGVuIGVsIG1vbWVudG8gZGUgbGEgaG9zcGl0YWxpemFjacOzbjwvbGk+DQo8bGk+bWFyY2FzOiBDYW50aWRhZCBkZSBtYXJjYXMgY29uZmlybWFkYXMgZGVsIGFzZWd1cmFkbzwvbGk+DQo8L3VsPg0KPC9saT4NCjwvdWw+DQo8dWw+DQo8bGk+VmFyaWFibGVzIG9yZGluYWxlcyAoMSkNCjx1bD4NCjxsaT5pbmdyZXNvOiBSYW5nbyBkZSBpbmdyZXNvczwvbGk+DQo8L3VsPg0KPC9saT4NCjwvdWw+DQo8dWw+DQo8bGk+RmVjaGEgKDEpDQo8dWw+DQo8bGk+RmVjaGFfSW5ncmVzbzogZmVjaGEgaW5ncmVzbyBob3NwaXRhbGl6YWNpw7NuIDwvbGk+DQo8L3VsPg0KPC9saT4NCjwvdWw+DQoNCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5HZW5lcmFtb3MgbGEgZXN0YWTDrXN0aWNhIGRlc2NyaXB0aXZhIGRlIGxvcyBkYXRvczsgZW4gZWxsYSBzZSBwdWVkZSB2aXN1YWxpemFyIHF1ZSBlcyBuZWNlc2FyaW8gcmVhbGl6YXIgbcOhcyBhZGVsYW50ZSBhbGd1bmFzIGNvbnZlcnNpb25lcyBlbiBsb3MgdGlwb3MgZGUgZGF0b3MgcXVlIHZpZW5lbiBwb3IgZGVmZWN0byAocG9yIGVqZW1wbG8gZWwgZXN0cmF0byBhcGFyZWNlIGNvbW8gdW5hIHZhcmlhYmxlIG51bcOpcmljYSkuIFBlcm8gYW50ZXMgZGUgY29udGludWFyIGNvbiBsYSBjb2RpZmljYWNpw7NuLCBwcm9jZWRlcmVtb3MgYSByZWFsaXphciB1biBicmV2ZSBhbsOhbGlzaXMgZGUgdmFsb3JlcyBww6lyZGlkb3MgcXVlIG5vcyBwZXJtaXRhbiByZWZpbmFyIGxhIGxpbXBpZXphIHJlcXVlcmlkYSBlbiBsb3MgZGF0b3MuPC9wPg0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgZXZhbCA9VFJVRX0NCnNraW1fd2l0aChudW1lcmljID0gbGlzdChoaXN0ID0gTlVMTCkpDQoNCmRhdGFfcmVob3NwICU+JSANCiAgZ3JvdXBfYnkoKSAlPiUNCiAgc2tpbSgpDQpgYGANCg0KYGBge3J9DQpyZXF1aXJlKHNjYWxlcykNCg0KZGF0YV9yZWhvc3AgJT4lDQogIGZpbHRlcihwYWdvX2hvc3AgPiAwKSAlPiUNCiAgZ3JvdXBfYnkoZmVjaGFfaW5ncmVzbykgJT4lDQogIHN1bW1hcmlzZV9hbGwofnN1bShwYWdvX2hvc3ApKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWZlY2hhX2luZ3Jlc28sIHk9cGFnb19ob3NwKSkgKw0KICBnZW9tX2xpbmUoKSArIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJQYWdvIEhvc3AgZW4gZWwgdGllbXBvIiwNCiAgICAgICAgIHg9ICJGZWNoYV9JbmdyZXNvIiwNCiAgICAgICAgIHkgPSAiUGFnbyBIb3NwIikgKw0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZG9sbGFyKSAtPiBwDQoNCnAgPC0gZ2dwbG90bHkocCkNCg0KcA0KIyBwICU+JQ0KIyAgIHRleHQgPSB+cGFzdGUwKCI8Yj5GZWNoYSBJbmdyZXNvOjxicj48L2I+IiwgZmVjaGFfaW5ncmVzbywNCiMgICAgICAgICAgICAgICAgICAiPGI+RmVjaGEgSW5ncmVzbzo8L2I+IiwgcGFnb19ob3NwKQ0KIyBnZ3Bsb3QoZGF0YV9yZWhvc3AsIGFlcyh4ID0gZmVjaGFfaW5ncmVzbywgeSA9IHJlaG9zcF9vbXMpKSArDQojICAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IGFzLmZhY3RvcihyZWhvc3Bfb21zKSksIHNpemUgPSAxKSArDQojICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIpKSArDQojICAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KPGEgaHJlZj0iI0luaWNpbyI+Vm9sdmVyIGFsIGluaWNpbzwvYT48L2xpPg0KDQoNCjxoMiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PGEgaWQ9IlBlcmRpZG9zIj5BbsOhbGlzaXMgZGUgUmVnaXN0cm9zIFDDqXJkaWRvczwvYT48L2gyPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkVuIGxhIGdyw6FmaWNhIHNpZ3VpZW50ZSBwb2RlbW9zIG9ic2VydmFyIHF1ZSBoYXkgZW4gdG90YWwgMyB2YXJpYWJsZXMgcXVlIG5vIGNvbnRpZW5lbiByZWdpc3Ryb3MgdmFjaW9zOiBlc3RyYXRvLCBlc3RhZG8gY2l2aWwgZSBpbmdyZXNvLjwvcD4NCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5BIG5pdmVsIGluZGl2aWR1YWwgZWwgcG9yY2VudGFqZSBkZSB2YWxvcmVzIHBlcmRpZG9zIHBhcmEgdG9kb3MgbG9zIGNhc29zIGVzIHN1cGVyaW9yIGFsIDI1JS4gRGUgZm9ybWEgY29tYmluYWRhIGhheSAzMTggcmVnaXN0cm9zIHZhY8Otb3MgZW4gaW5ncmVzbywgMjU5IGVuIHPDs2xvIGVsIGVzdHJhdG8geSAxNDQgZW4gZWwgZXN0YWRvIGNpdmlsLCBlbCByZXN0byAgZGUgbG9zIGNhbXBvcyBudWxvcyBjb3JyZXNwb25kZSBhIGNvbWJpbmFjaW9uZXMgZW50cmUgZG9zIHZhcmlhYmxlczsgcG9yIGVuZGUgbm8gcG9kZW1vcyBkZWNpciBxdWUgbGEgcHJvYmFiaWxpZGFkIGRlIHF1ZSBmYWx0ZSB1biB2YWxvciBkZXBlbmRlIHNvbG8gZGVsIHZhbG9yIG9ic2VydmFkbywgeSB1c2FyIHVuIG3DqXRvZG8gcGFyYSBpbXB1dGFybG8gKGxhIGZvcm1hIG5vIGVzIGFsZWF0b3JpYSkuPC9wPg0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGV2YWwgPVRSVUUsIGVjaG8gPSBGQUxTRX0NCmFnZ3IoZGF0YV9yZWhvc3AsIA0KICAgICBjb21iaW5lZCA9IEZBTFNFLCANCiAgICAgcHJvcCA9IGMoVFJVRSwgVFJVRSksDQogICAgIGNvbCA9IGMoIiNDQ0U1RkYiLCAiIzAwNjZDQyIpLA0KICAgICBjZXguYXhpcyA9IDAuNywNCiAgICAgZ2FwID0gMS41LA0KICAgICBib3JkZXIgPSBOQSwNCiAgICAgYmFycyA9IEZBTFNFLA0KICAgICB5bGFiID0gYygiUHJvcG9yY2nDs24gZGUgRGF0b3MgUGVyZGlkb3MiLCAiQ29tYmluYWNpb25lcyIpKQ0KYGBgDQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+UGFyYSBjb3Jyb2JvcmFyIHF1ZSBsb3MgZGF0b3Mgbm8gZmFsdGFuIGFsIGF6YXIsIHNlIHJlYWxpemEgdW4gZ3JhZmljbyBkZSBjb3JyZWxhY2nDs24gcXVlIG5vcyBheXVkZSBhIHZlcmlmaWNhciBsbyBhbnRlcmlvci4gUGFyYSBlbGxvLCBjb25zdHJ1aW1vcyB1biBkYXRhZnJhbWUgcXVlIGluZGlxdWUgc2kgZWwgY2FtcG8gZXN0w6EgdmFjaW8gKDEpIG8gbm8gKDApOyBjb24gZXN0YSBpbmZvcm1hY2nDs24gc2VsZWNjaW9uYW1vcyBzw7NsbyBhcXVlbGxhcyBjb2x1bW5hcyBxdWUgdGllbmVuIGFsZ3Vub3MgKG5vIHRvZG9zKSBzdXMgcmVnaXN0cm9zIG51bG9zIHkgZmluYWxtZW50ZSBjcmVhbW9zIGxhIG1hdHJpeCBkZSBjb3JyZWxhY2nDs24uPC9wPg0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgZXZhbCA9VFJVRX0NCm1hdHJpeF9taXNzIDwtIGFzLmRhdGEuZnJhbWUoYWJzKGlzLm5hKGRhdGFfcmVob3NwKSkpDQpvbmx5X21pc3MgPC0gbWF0cml4X21pc3NbLHNhcHBseShtYXRyaXhfbWlzcywgc2QpID4gMF0NCmNvcnJfbWlzcyA8LSByb3VuZChjb3Iob25seV9taXNzKSwzKQ0KcC5tYXQgPC0gY29yX3BtYXQob25seV9taXNzKQ0KDQpnZ2NvcnJwbG90KGNvcnJfbWlzcywgDQogICAgICAgICAgIHR5cGUgPSAibG93ZXIiLA0KICAgICAgICAgICBvdXRsaW5lLmNvbCA9ICJ3aGl0ZSIsDQogICAgICAgICAgIHAubWF0ID0gcC5tYXQsDQogICAgICAgICAgIHNpZy5sZXZlbCA9IDAuMDUsDQogICAgICAgICAgIGdndGhlbWUgPSBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsLA0KICAgICAgICAgICBsYWIgPSBUUlVFLA0KICAgICAgICAgICBjb2xvcnMgPSBjKCIjOTlDQ0ZGIiwgIndoaXRlIiwgIiMwMDY2Q0MiKSkgKyANCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhY2lvbiBlbnRyZSBkYXRvcyBwZXJkaWRvcyBwb3IgY29sdW1uYSIpDQpgYGANCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5EYWRvIHF1ZSBjb24gbGEgYW50ZXJpb3IgbWF0cml4IGEgdW4gbml2ZWwgZGUgc2lnbmlmaWNhbmNpYSBkZWwgNSUgc2UgY29tcHJ1ZWJhIGxhIGhpcMOzdGVzaXMgaW5pY2lhbCBkZSBubyBhbGVhdG9yaWVkYWQsIHNlIHByb2NlZGUgYSBjb25zdHJ1aXIgdW5hIHRlcmNlcmEgY2F0ZWdvcsOtYSBwYXJhIGNhZGEgdW5hIGRlIGxhcyB2YXJpYWJsZXMgcXVlIHBvc2VlIGNhbXBvcyB2YWPDrW9zLjwvcD4NCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5QYXJhIGVzdGltYXIgc2kgZXhpc3RlIHVuYSBhc29jaWFjacOzbiBlbnRyZSBsYXMgdmFyaWFibGVzIHF1ZSBwdWVkYSBkZXJpdmFyc2UgZW4gY29saW5lYWxpZGFkLCBzZSBwcm9jZWRlIHByaW1lcm8gYSB2ZXJpZmljYXIgcXVlIGxhcyB2YXJpYWJsZXMgbm8gcG9zZWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCwgdW5hIHZleiByZWFsaXphZG8gZXN0bywgc2UgZWxpZ2UgZWwgdGVzdCBkZSBTcGVhcm1hbiBwYXJhIGhhbGxhciBsYSBjb3JyZWxhY2nDs24gbGluZWFsIHBvciBhdHJpYnV0by48L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0KZGF0YV9yZWhvc3AgJT4lDQogIHNlbGVjdChwYWdvX2hvc3AsIA0KICAgICAgICAgZGlhc191Y2ksDQogICAgICAgICBkaWFzX3VjZSwNCiAgICAgICAgIGRpYXNfaG9zcCwNCiAgICAgICAgIHJlaG9zcF9vbXMpIC0+IGRhdGFfbnVtDQoNCm5vcm1fdGVzdCA8LSBsYXBwbHkoZGF0YV9udW0sIGxpbGxpZS50ZXN0KQ0KbHJlcyA8LSBzYXBwbHkobm9ybV90ZXN0LCBgW2AsIGMoInN0YXRpc3RpYyIsInAudmFsdWUiKSkNCnQobHJlcykNCmBgYA0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkxvcyByZXN1bHRhZG9zIGNvbmZpcm1hbiBxdWUgbmluZ3VuYSBkZSBsYXMgdmFyaWFibGVzIHBlc2VudGEgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIHkgbGFzIGNvcnJlbGFjaW9uZXMgcmVsYWNpb25hZGFzIGEgY29udGludWFjacOzbiwgdmVyaWZpY2FuIHBvc2libGVzIGFzb2NpYWNpb25lcyBlbnRyZSBsYXMgdmFyaWFibGVzIGRlIGxvcyBkw61hcyBlbiBxdWUgZWwgcGFjaWVudGUgZXN0dXZvIGludGVybmFkbyBlbiBsYSBVbmlkYWQgZGUgQ3VpZGFkb3MgSW50ZW5zaXZvcywgZW4gbGEgVW5pZGFkIGRlIEN1aWRhZG9zIEVzcGVjaWFsZXMgeSBsb3MgZMOtYXMgcXVlIGVsIHBhY2llbnRlIGVzdHV2byBob3NwaXRhbGl6YWRvLiBQb3IgY29ub2NpbWllbnRvIGRlIGZhY3RvLCBsYSByZWxhY2nDs24gZW50cmUgbGEgdmFyaWFibGUgImRpYXNfdWNpIiB5ICJkaWFzX3VjZSIgZXMgZW50ZW5kaWJsZSwgeWEgcXVlIGN1YW5kbyB1biBwYWNpZW50ZSBxdWUgaGEgcGFzYWRvIHBvciBsYSBVbmlkYWQgZGUgQ3VpZGFkb3MgSW50ZW5zaXZvcyBwYXPDsyBzdSBtb21lbnRvIGRlIGNyaXNpcyB5IHN1IGVzdGFkbyBkZSBzYWx1ZCBlcyBtw6FzIGVzdGFibGUsIHN1ZWxlIHNlciByZW1pdGlkbyBhIGxhIFVuaWRhZCBkZSBDdWlkYWRvcyBFc3BlY2lhbGVzLiA8L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0KY29ycl9udW0gPC0gcm91bmQoY29yKGRhdGFfbnVtKSw0KQ0KcC5tYXQgPC0gY29yX3BtYXQoZGF0YV9udW0sIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQoNCmdnY29ycnBsb3QoY29ycl9udW0sIA0KICAgICAgICAgICB0eXBlID0gImxvd2VyIiwNCiAgICAgICAgICAgb3V0bGluZS5jb2wgPSAid2hpdGUiLA0KICAgICAgICAgICBwLm1hdCA9IHAubWF0LA0KICAgICAgICAgICBzaWcubGV2ZWwgPSAwLjA1LA0KICAgICAgICAgICBnZ3RoZW1lID0gZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCwNCiAgICAgICAgICAgbGFiID0gVFJVRSwNCiAgICAgICAgICAgY29sb3JzID0gYygiIzk5Q0NGRiIsICJ3aGl0ZSIsICIjMDA2NkNDIikpICsgDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYWNpb24gZW50cmUgdmFyaWFibGVzIG51bcOpcmljYXMiKQ0KYGBgDQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+TGFzIGNvcnJlbGFjaW9uZXMgb2J0ZW5pZGFzIG5vIGN1bXBsZW4gdW4gdW1icmFsIHN1ZmljaWVudGUgcGFyYSBjb25zaWRlcmFybGFzIGltcG9ydGFudGVzLCBwb3IgZW5kZSBzZSBwcm9jZWRlIGEgY29uc2VydmFybGFzIHkgZXZhbHVhciBtw6FzIGFkZWxhbnRlIHNpIGVzIHByZWNpc28gZWxpbWluYXJsYXMgZGVmaW5pdGl2YW1lbnRlIGFsIGNvbnN0cnVpciB1biBtb2RlbG8gY29uIGZpbmVzIHByZWRpY3Rpdm9zLiBQb3Igb3RybyBsYWRvLCBsYSB2YXJpYWJsZSBjYXRlZ29yw61hIHkgZGlhZ27Ds3N0aWNvIGVzdMOhbiBhbHRhbWVudGUgY29ycmVsYWNpb25hZGFzIGNvbiBsYSB2YXJpYWJsZSBlbmTDs2dlbmEsIHBvciBsbyBxdWUgZXMgbmVjZXNhcmlvIGVsaW1pbmFybGFzIGRlbCBhbsOhbGlzaXMsIHBhcmEgbm8gaW5jdXJyaXIgZW4gcG9zaWJsZXMgc29icmVhanVzdGVzIGVuIGxhIGV0YXBhIGRlIG1vZGVsYWRvLjwvcD4NCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5UZW5pZW5kbyBlbiBjdWVudGEgZWwgYW7DoWxpc2lzIGRlIGRhdG9zIHBlcmRpZG9zIG8gbnVsb3MsIHNlIGRlY2lkZSBkZXNjYXJ0YXIgbGEgdmFyaWFibGUgaW5ncmVzbyB5YSBxdWUgY29udGllbmUgbWFzIGRlIHVuIDMwJSBlbiBkYXRvcyBwZXJkaWRvcy48L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0KDQpkYXRhX3JlaG9zcCAlPiUNCiAgbXV0YXRlKGVzdHJhdG8gPSBpZmVsc2UoaXMubmEoZXN0cmF0bykgfCBlc3RyYXRvID09IC0xIHwgZXN0cmF0byA9PSAwLCAiU2luIEluZm9ybWFjaW9uIiwgZXN0cmF0byksDQogICAgICAgICBlc3RfY2l2aWwgPSBpZmVsc2UoaXMubmEoZXN0X2NpdmlsKSwgIlNpbiBJbmZvcm1hY2lvbiIsIGVzdF9jaXZpbCksDQogICAgICAgICBpbmdyZXNvID0gaWZlbHNlKGlzLm5hKGluZ3Jlc28pLCAiU2luIEluZm9ybWFjaW9uIiwgaW5ncmVzbyksDQogICAgICAgICBwcm92ZWVkb3IgPSBpZmVsc2UoaXMubmEocHJvdmVlZG9yKSwgIlNpbiBJbmZvcm1hY2lvbiIsIHByb3ZlZWRvciksDQogICAgICAgICBxdWlydXIgPSBpZmVsc2UocXVpcnVyID09IDEsICdTaScsICdObycpLA0KICAgICAgICAgZWRhZCA9IGNhc2Vfd2hlbiggZWRhZCA8PSAzMCB+ICIxOC0zMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlZGFkID49IDMxICYgZWRhZCA8PSA0MCB+ICIzMS00MCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlZGFkID49IDQxICYgZWRhZCA8PSA1MCB+ICI0MS01MCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlZGFkID49IDUxICYgZWRhZCA8PSA2MCB+ICI1MS02MCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlZGFkID49IDYxICYgZWRhZCA8PSA3MCB+ICI2MS03MCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlZGFkID49IDcxICYgZWRhZCA8PSA4MCB+ICI3MS04MCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlZGFkID49IDgxIH4gIjgxKyIpLA0KICAgICAgICAgbWFyY2FzID0gY3V0KG1hcmNhcywgYnJlYWtzID0gKDA6MykqMiwgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSwNCiAgICAgICAgIGVzdF9jaXZpbCA9IGFzLmZhY3Rvcihlc3RfY2l2aWwpLA0KICAgICAgICAgZ2VuZXJvID0gYXMuZmFjdG9yKGdlbmVybyksDQogICAgICAgICBjaXVkYWQgPSBhcy5mYWN0b3IoY2l1ZGFkKSwNCiAgICAgICAgIHF1aXJ1ciA9IGFzLmZhY3RvcihxdWlydXIpLA0KICAgICAgICAgcHJvdmVlZG9yID0gYXMuZmFjdG9yKHByb3ZlZWRvciksDQogICAgICAgICByYW1vID0gYXMuZmFjdG9yKHJhbW8pLA0KICAgICAgICAgZWRhZCA9IGFzLmZhY3RvcihlZGFkKSwNCiAgICAgICAgIGVzdHJhdG8gPSBhcy5mYWN0b3IoZXN0cmF0bykpICU+JQ0KICBzZWxlY3QoLWRpYWdub3MsIC1jYXRlZ29yaWEsIC1mZWNoYV9pbmdyZXNvLCAtaW5ncmVzbykgLT4gZGF0YV9yZWhvc3ANCg0Kc3RyKGRhdGFfcmVob3NwKQ0KYGBgDQoNCjxhIGhyZWY9IiNJbmljaW8iPlZvbHZlciBhbCBpbmljaW88L2E+PC9saT4NCg0KPGgyIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48YSBpZD0iQW5hbGlzaXMiPkFuw6FsaXNpcyBFeHBsb3JhdG9yaW88L2E+PC9oMj4NCg0KPGgzIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48YSBpZD0iQW5hbGlzaXNDb24iPkFuw6FsaXNpcyB1bml2YXJpYWRvIC0gdmFyaWFibGVzIGNvbnRpbnVhczwvYT48L2gzPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkVzIGV2aWRlbnRlIGxhIGV4aXN0ZW5jaWEgdGFtYmnDqW4sIGRlIHZhbG9yZXMgYXTDrXBpY29zIG11eSBtYXJjYWRvcyB0YW50byBlbiBlbCBudW3DqXJvIGRlIGTDrWFzIGRlIGhvc3BpdGFsaXphY2nDs24sIGNvbW8gZW4gbG9zIG7Dum1lcm9zIGRlIGTDrWFzIHF1ZSBlbCBwYWNpZW50ZSBlc3R1dm8gZW4gbGEgVW5pZGFkIGRlIEN1aWRhZG8gSW50ZW5zaXZvIHkgRXNwZWNpYWwsIGVuIGTDs25kZSBsb3MgdmFsb3JlcyBhdMOtcGljb3MgbcOhcyBncmFuZGVzIHN1Y2VkZW4gZW4gbG9zIGV2ZW50b3MgcXVlIHRlcm1pbmFyb24gZW4gcmVob3NwaXRhbGl6YWNpw7NuLjwvcD4NCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5Db24gZWwgYW7DoWxpc2lzIGFudGVyaW9yIG5vIHPDs2xvIHNlIGxvZ3JhIGlkZW50aWZpY2FyIHZhcmlhYmxlcyBjb24gcHJlc2VuY2lhIGRlIHZhbG9yZXMgYXTDrXBpY29zLCBzaW5vIHF1ZSB0YW1iacOpbiBlcyBwb3NpYmxlIGV2aWRlbmNpYXIgcXVlIGxvcyBkYXRvcyBzZSBlbmN1ZW50cmFuIGFsdGFtZW50ZSBkZXNiYWxhbmNlYWRvcy4gUG9yIGVuZGUsIGFudGVzIGRlIGNvbnRpbnVyIGNvbiBsYSBleHBsb3JhY2nDs24gZGUgbG9zIGRhdG9zIHNlIHByb2NlZGUgYSB0cmF0YXIgYW1ib3MgcHJvYmxlbWFzLiBFbiBlbCBjYXNvIGRlIGxvcyBvdXRsaWVycyBzZSB0cnVuY2Fyw6EgZW4gbG9zIGNhc29zIGVuIHF1ZSBzZWEgbmVjZXNhcmlvLCBpbXB1dGFuZG8gbG9zIHZhbG9yZXMgcXVlIHN1cGVyZW4gY2llcnRvIGzDrW1pdGUgZW4gZWwgcGVyY250aWwsIHRhbnRvIG1heW9yIGNvbW8gbWVub3IuPC9wPg0KDQpgYGB7cn0NCmRhdGFfcmVob3NwICU+JQ0KICBtdXRhdGUocGFnb19ob3NwID0gaWZlbHNlKHF1aXJ1ciA9PSAiU2kiICYgcmVob3NwX29tcyA9PSAwLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRsaWVyKG15ZGF0YSA9IGZpbHRlcihkYXRhX3JlaG9zcCwgcXVpcnVyID09ICJTaSIgJiByZWhvc3Bfb21zID09IDApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gInBhZ29faG9zcCIsIHFfbWluID0gMCwgcV9tYXggPSAwLjk3KSwgcGFnb19ob3NwKSwNCiAgICAgICAgIHBhZ29faG9zcCA9IGlmZWxzZShxdWlydXIgPT0gIlNpIiAmIHJlaG9zcF9vbXMgPT0gMSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0bGllcihteWRhdGEgPSBmaWx0ZXIoZGF0YV9yZWhvc3AsIHF1aXJ1ciA9PSAiU2kiICYgcmVob3NwX29tcyA9PSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gInBhZ29faG9zcCIsIHFfbWluID0gMCwgcV9tYXggPSAwLjk4KSwgcGFnb19ob3NwKSwNCiAgICAgICAgIHBhZ29faG9zcCA9IGlmZWxzZShxdWlydXIgPT0gIk5vIiAmIHJlaG9zcF9vbXMgPT0gMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0bGllcihteWRhdGEgPSBmaWx0ZXIoZGF0YV9yZWhvc3AsIHF1aXJ1ciA9PSAiTm8iICYgcmVob3NwX29tcyA9PSAwKSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICJwYWdvX2hvc3AiLCBxX21pbiA9IDAsIHFfbWF4ID0gMC45NyksIHBhZ29faG9zcCksIA0KICAgICAgICAgcGFnb19ob3NwID0gaWZlbHNlKHF1aXJ1ciA9PSAiTm8iICYgcmVob3NwX29tcyA9PSAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRsaWVyKG15ZGF0YSA9IGZpbHRlcihkYXRhX3JlaG9zcCwgcXVpcnVyID09ICJObyIgJiByZWhvc3Bfb21zID09IDEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gInBhZ29faG9zcCIsIHFfbWluID0gMCwgcV9tYXggPSAwLjk4KSwgcGFnb19ob3NwKSwNCiAgICAgICAgIGRpYXNfaG9zcCA9IGlmZWxzZShyZWhvc3Bfb21zID09IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGxpZXIobXlkYXRhID0gZmlsdGVyKGRhdGFfcmVob3NwLCByZWhvc3Bfb21zID09IDApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICJkaWFzX2hvc3AiLCBxX21pbiA9IDAsIHFfbWF4ID0gMC45OSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0bGllcihteWRhdGEgPSBmaWx0ZXIoZGF0YV9yZWhvc3AsIHJlaG9zcF9vbXMgPT0gMSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gImRpYXNfaG9zcCIsIHFfbWluID0gMCwgcV9tYXggPSAwLjk5KSksDQogICAgICAgICBkaWFzX3VjaSA9IGlmZWxzZShyZWhvc3Bfb21zID09IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0bGllcihteWRhdGEgPSBmaWx0ZXIoZGF0YV9yZWhvc3AsIHJlaG9zcF9vbXMgPT0gMCAmIGRpYXNfdWNpID4gMCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gImRpYXNfdWNpIiwgcV9taW4gPSAwLCBxX21heCA9IDAuOTkpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAsIGRpYXNfdWNpKSwNCiAgICAgICAgIGRpYXNfdWNlID0gaWZlbHNlKHJlaG9zcF9vbXMgPT0gMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRsaWVyKG15ZGF0YSA9IGZpbHRlcihkYXRhX3JlaG9zcCwgcmVob3NwX29tcyA9PSAwICYgZGlhc191Y2UgPiAwKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAiZGlhc191Y2UiLCBxX21pbiA9IDAsIHFfbWF4ID0gMC45OSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICwgZGlhc191Y2kpKSAtPiBkYXRhX3JlaG9zcA0KYGBgDQoNCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnk7Ij5TZSBwdWVkZSBvYnNlcnZhciBxdWUgdGFudG8gZW4gZWwgbnVtw6lybyBkZSBtYXJjYXMgY29tbyBlbiBsYSB2YXJpYWJsZSBkZSBwYWdvLCBjb3JyZXNwb25kaWVudGUgYWwgcHJpbWVyIGRpYWduw7NzdGljbywgbm8gcGFyZWNlIGhhYmVyIHVuYSBkaWZlcmVuY2lhIHNpZ25pZmljYXRpdmEgZW4gbGEgZGlzdHJpYnVjacOzbiBhbCBkaXNjcmltaW5hciBwb3IgbGEgdmFyaWFibGUgb2JqZXRpdm8gYmluYXJpYSwgZXMgZGVjaXIsIGVudHJlIGxvcyBjYXNvcyBkZSByZWhvc3BpdGFsaXphY2nDs24gKDEpIHkgY2Fzb3MgZGUgbm8gcmVob3NwaXRhbGl6YWNpw7NuICgwKS4gQWRpY2lvbmFsbWVudGUsIGxhIGRpc3RpYnVjacOzbiBlbiBhbWJhcyB2YXJpYWJsZXMgbm8gZXMgc2ltw6l0cmljYS4gRW4gZWwgY2FzbyBkZSBsYXMgbWFyY2FzIHNlIG9ic2VydmEgdW5hIGFzaW1ldHLDrWEgcG9zaXRpdmEgbyBzZXNnYWRhIGEgbGEgZGVyZWNoYSB5IGRlIG1hbmVyYSBzaW1pbGFyLCBhdW5xdWUgbWVub3MgbWFyY2FkYSwgcGFyYSBlbCBjYXNvIGRlbCBwYWdvIGVuIGVsIHByaW1lciBkaWFnbsOzc3RpY28uPC9wPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkxvcyBkYXRvcyBzZSBlbmN1ZW50cmFuIGJhc3RhbnRlIGRpc3BlcnNvcyB5IHJlZmxlamFuIHByZXNlbmNpYSBkZSBvdXRsaWVycy48L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0KDQpwNSA8LSBteWJveHBsb3QobXlkYXRhID0gZmlsdGVyKGRhdGFfcmVob3NwLCBwYWdvX2hvc3AgPiAwKSwgDQogICAgICAgICAgICAgICAgbXlleHBvc3VyZSA9ICJyZWhvc3Bfb21zIiwgDQogICAgICAgICAgICAgICAgbXlvdXRjb21lID0gInBhZ29faG9zcCIsIA0KICAgICAgICAgICAgICAgIG15dGl0bGUgPSAiUGFnbyBob3NwaXRhbGl6YWNpw7NuIiwgDQogICAgICAgICAgICAgICAgbXlsYWJlbF94ID0gIiIsIA0KICAgICAgICAgICAgICAgIG15bGFiZWxfeSA9ICJQYWdvIERpYWciLCANCiAgICAgICAgICAgICAgICBteV9maWxsID0gIiIpDQoNCnA2IDwtIG15Ym94cGxvdChteWRhdGEgPSBkYXRhX3JlaG9zcCwgDQogICAgICAgICAgICAgICAgbXlleHBvc3VyZSA9ICJyZWhvc3Bfb21zIiwgDQogICAgICAgICAgICAgICAgbXlvdXRjb21lID0gImRpYXNfaG9zcCIsIA0KICAgICAgICAgICAgICAgIG15dGl0bGUgPSAiVG90YWwgZGlhcyBob3NwaXRhbGl6YWRvIiwgDQogICAgICAgICAgICAgICAgbXlsYWJlbF94ID0gIiIsIA0KICAgICAgICAgICAgICAgIG15bGFiZWxfeSA9ICJEaWFzIGhvc3BpdGFsaXphY2nDs24iLCANCiAgICAgICAgICAgICAgICBteV9maWxsID0gIiIpDQoNCnA3IDwtIG15Ym94cGxvdChteWRhdGEgPSBmaWx0ZXIoZGF0YV9yZWhvc3AsIGRpYXNfdWNpID4gMCksIA0KICAgICAgICAgICAgICAgIG15ZXhwb3N1cmUgPSAicmVob3NwX29tcyIsIA0KICAgICAgICAgICAgICAgIG15b3V0Y29tZSA9ICJkaWFzX3VjaSIsIA0KICAgICAgICAgICAgICAgIG15dGl0bGUgPSAgIlRvdGFsIGTDrWFzIFVDSSIsIA0KICAgICAgICAgICAgICAgIG15bGFiZWxfeCA9ICIiLCANCiAgICAgICAgICAgICAgICBteWxhYmVsX3kgPSAiRGlhcyBVQ0kiLCANCiAgICAgICAgICAgICAgICBteV9maWxsID0gIiIpDQoNCnA4IDwtIG15Ym94cGxvdChteWRhdGEgPSBmaWx0ZXIoZGF0YV9yZWhvc3AsIGRpYXNfdWNlID4gMCksIA0KICAgICAgICAgICAgICAgIG15ZXhwb3N1cmUgPSAicmVob3NwX29tcyIsIA0KICAgICAgICAgICAgICAgIG15b3V0Y29tZSA9ICJkaWFzX3VjZSIsIA0KICAgICAgICAgICAgICAgIG15dGl0bGUgPSAiVG90YWwgZMOtYXMgVUNFIiwgDQogICAgICAgICAgICAgICAgbXlsYWJlbF94ID0gIiIsIA0KICAgICAgICAgICAgICAgIG15bGFiZWxfeSA9ICJEaWFzIFVDRSIsIA0KICAgICAgICAgICAgICAgIG15X2ZpbGwgPSAiIikNCg0KI2dyaWQuYXJyYW5nZShwNSwgcDYsIHA3LCBwOCwgbnJvdyA9IDIsIG5jb2wgPSAyKQ0KDQpwNSA8LSBnZ3Bsb3RseShwNSkNCnA2IDwtIGdncGxvdGx5KHA2KQ0KcDcgPC0gZ2dwbG90bHkocDcpDQpwOCA8LSBnZ3Bsb3RseShwOCkNCg0Kc3VicGxvdChwNywgcDgsIHA1LCBwNiwgbnJvd3MgPSAyLCBuY29sKDIpKQ0KDQoNCg0KYGBgDQoNCjxoMyBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PGEgaWQ9IkFuYWxpc2lzQ2FyIj5BbsOhbGlzaXMgdW5pdmFyaWFkbyAtIHZhcmlhYmxlcyBjYXJkaW5hbGVzPC9hPjwvaDM+DQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+T2JzZXJ2YW5kbyBsYXMgdmFyaWFibGVzIGNhdGVnw7NyaWNhcyBsYSBkaWZlcmVuY2lhIGVudHJlIGxhIHByb2JhYmlsaWRhZCBkZSBxdWUgZWwgZXZlbnRvIG9jdXJyYSAoaGF5YSByZWhvc3BpdGFsaXphY2nDs24pIG8gbm8sIHNlIHB1ZWRlIGV2aWRlbmNpYXIgc8OzbG8gZW4gYWxndW5hcyBjbGFzZXMgcG9yIGNhdGVnb3LDrWEsIHBlcm8gZW4gZ2VuZXJhbCwgbGFzIHByb3BvcmNpb25lcyBzdWVsZW4gc2VyIGJhc3RhbnRlcyBzaW1pbGFyZXMsIHBvciBsbyBxdWUgbm8gZXMgcG9zaWJsZSBlbGFib3JhciBhIHByaW9yaSB1bmEgaGlww7N0ZXNpcyBxdWUgZXN0aXB1bGUgZGlmZXJlbmNpYXMgc2lnbmlmaWNhdGl2YXMgZW4gbGFzIGRpc3RyaWJ1Y2lvbmVzLCBwb3IgbG8gbWVub3MgcGFyYSBuaW5ndW5hIGRlIGxhcyBkb3MgdmFyaWFibGVzIHJlbGFjaW9uYWRhcyBlbiBlbCBncsOhZmljbyBhIGNvbnRpbnVhY2nDs24uPC9wPg0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgZXZhbCA9VFJVRX0NCg0KcDkgPC0gbXlnZW9tX2JhcihteWRhdGEgPSBkYXRhX3JlaG9zcCwgDQogICAgICAgICAgICAgICAgIG15ZXhwb3N1cmUgPSAiZWRhZCIsIA0KICAgICAgICAgICAgICAgICBteW91dGNvbWUgPSAicmVob3NwX29tcyIsIA0KICAgICAgICAgICAgICAgICBteXRpdGxlID0gIkVkYWQiLCANCiAgICAgICAgICAgICAgICAgbXlsYWJlbF94ID0gIiIsIA0KICAgICAgICAgICAgICAgICBteWxhYmVsX3kgPSAiRnJlY3VlbmNpYSIsIA0KICAgICAgICAgICAgICAgICBteV9maWxsID0gIlJlaG9zcGl0YWxpemFjacOzbiIsIA0KICAgICAgICAgICAgICAgICBteV9hbmdsZSA9IE5VTEwsDQogICAgICAgICAgICAgICAgIG15X2xlZ2VuZCA9ICJyaWdodCIpDQoNCnAxMCA8LSBteWdlb21fYmFyKG15ZGF0YSA9IGRhdGFfcmVob3NwLCANCiAgICAgICAgICAgICAgICAgIG15ZXhwb3N1cmUgPSAiZXN0cmF0byIsIA0KICAgICAgICAgICAgICAgICAgbXlvdXRjb21lID0gInJlaG9zcF9vbXMiLCANCiAgICAgICAgICAgICAgICAgIG15dGl0bGUgPSAiRXN0cmF0byIsIA0KICAgICAgICAgICAgICAgICAgbXlsYWJlbF94ID0gIiIsIA0KICAgICAgICAgICAgICAgICAgbXlsYWJlbF95ID0gIkZyZWN1ZW5jaWEiLCANCiAgICAgICAgICAgICAgICAgIG15X2ZpbGwgPSAiUmVob3NwaXRhbGl6YWNpw7NuIiwgDQogICAgICAgICAgICAgICAgICBteV9hbmdsZSA9IE5VTEwsDQogICAgICAgICAgICAgICAgICBteV9sZWdlbmQgPSAibm9uZSIpDQoNCmdyaWQuYXJyYW5nZShwOSwNCiAgICAgICAgICAgICBwMTApDQoNCiNwOSA8LSBnZ3Bsb3RseShwOSkNCiNwMTAgPC0gZ2dwbG90bHkocDEwKQ0KDQojc3VicGxvdChwOSwgcDEwLCBucm93cyA9IDIpDQoNCg0KYGBgDQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+UG9yIG90cm8gbGFkbywgZWwgYXRyaWJ1dG8gcXVlIGluZGljYSBlbCBoZWNobyBkZSBxdWUgc2UgaGF5YW4gcmVhbGl6YWRvIHByb2NlZGltaWVudG9zIHF1aXLDunJnaWNvcyBkdXJhbnRlIGxhIHByaW1lcmEgaG9zcGl0YWxpemFjacOzbiBtdWVzdHJhbiBjaWVydGEgZGlmZXJlbmNpYSBlbiBsYSBkaXN0cmlidWnDs24gcG9yIGdydXBvOyBlcyBtw6FzIHByb2JhYmxlIHF1ZSBsYSBwZXJzb25hIGRlYmEgc2VyIHJlaG9zcGl0YWxpemFkYSBkZSBudWV2by48L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0KDQpwMTQgPC0gbXlnZW9tX2JhcihteWRhdGEgPSBkYXRhX3JlaG9zcCwgDQogICAgICAgICAgICAgICAgICBteWV4cG9zdXJlID0gInF1aXJ1ciIsIA0KICAgICAgICAgICAgICAgICAgbXlvdXRjb21lID0gInJlaG9zcF9vbXMiLCANCiAgICAgICAgICAgICAgICAgIG15dGl0bGUgPSAiUHJvYyBxdWlyw7pyZ2ljbyIsIA0KICAgICAgICAgICAgICAgICAgbXlsYWJlbF94ID0gIiIsIA0KICAgICAgICAgICAgICAgICAgbXlsYWJlbF95ID0gIkZyZWN1ZW5jaWEiLCANCiAgICAgICAgICAgICAgICAgIG15X2ZpbGwgPSAiUmVob3NwaXRhbGl6YWNpw7NuIiwgDQogICAgICAgICAgICAgICAgICBteV9hbmdsZSA9IE5VTEwsDQogICAgICAgICAgICAgICAgICBteV9sZWdlbmQgPSAiYm90dG9tIikNCg0KcDE3IDwtIG15Z2VvbV9iYXIobXlkYXRhID0gZGF0YV9yZWhvc3AsIA0KICAgICAgICAgICAgICAgICAgbXlleHBvc3VyZSA9ICJtYXJjYXMiLCANCiAgICAgICAgICAgICAgICAgIG15b3V0Y29tZSA9ICJyZWhvc3Bfb21zIiwgDQogICAgICAgICAgICAgICAgICBteXRpdGxlID0gIk1hcmNhcyIsIA0KICAgICAgICAgICAgICAgICAgbXlsYWJlbF94ID0gIiIsIA0KICAgICAgICAgICAgICAgICAgbXlsYWJlbF95ID0gIkZyZWN1ZW5jaWEiLCANCiAgICAgICAgICAgICAgICAgIG15X2ZpbGwgPSAiUmVob3NwaXRhbGl6YWNpw7NuIiwgDQogICAgICAgICAgICAgICAgICBteV9hbmdsZSA9IE5VTEwsDQogICAgICAgICAgICAgICAgICBteV9sZWdlbmQgPSAiYm90dG9tIikNCg0KZ3JpZC5hcnJhbmdlKHAxNCwNCiAgICAgICAgICAgICAgcDE3LA0KICAgICAgICAgICAgICBuY29sID0gMSwNCiAgICAgICAgICAgICAgbnJvdyA9IDIpDQoNCiNwMTQgPC0gZ2dwbG90bHkocDE0KQ0KI3AxNyA8LSBnZ3Bsb3RseShwMTcpDQoNCiNzdWJwbG90KHAxNCwgcDE3LCBuY29sKDEpLCBucm93cyA9IDIpDQoNCg0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID0gRkFMU0V9DQoNCnAxNSA8LSBteWdlb21fYmFyKG15ZGF0YSA9IGRhdGFfcmVob3NwLCANCiAgICAgICAgICAgICAgICAgIG15ZXhwb3N1cmUgPSAicmFtbyIsIA0KICAgICAgICAgICAgICAgICAgbXlvdXRjb21lID0gInJlaG9zcF9vbXMiLCANCiAgICAgICAgICAgICAgICAgIG15dGl0bGUgPSAiUmFtbyBTZWd1cm8iLCANCiAgICAgICAgICAgICAgICAgIG15bGFiZWxfeCA9ICIiLCANCiAgICAgICAgICAgICAgICAgIG15bGFiZWxfeSA9ICJGcmVjdWVuY2lhIiwgDQogICAgICAgICAgICAgICAgICBteV9maWxsID0gIlJlaG9zcGl0YWxpemFjacOzbiIsIA0KICAgICAgICAgICAgICAgICAgbXlfYW5nbGUgPSBOVUxMLA0KICAgICAgICAgICAgICAgICAgbXlfbGVnZW5kID0gIm5vbmUiKQ0KDQpwMTYgPC0gbXlnZW9tX2JhcihteWRhdGEgPSBkYXRhX3JlaG9zcCwgDQogICAgICAgICAgICAgICAgICBteWV4cG9zdXJlID0gImVzdF9jaXZpbCIsIA0KICAgICAgICAgICAgICAgICAgbXlvdXRjb21lID0gInJlaG9zcF9vbXMiLCANCiAgICAgICAgICAgICAgICAgIG15dGl0bGUgPSAiRXN0YWRvIGNpdmlsIiwgDQogICAgICAgICAgICAgICAgICBteWxhYmVsX3ggPSAiIiwgDQogICAgICAgICAgICAgICAgICBteWxhYmVsX3kgPSAiRnJlY3VlbmNpYSIsIA0KICAgICAgICAgICAgICAgICAgbXlfZmlsbCA9ICJSZWhvc3BpdGFsaXphY2nDs24iLCANCiAgICAgICAgICAgICAgICAgIG15X2FuZ2xlID0gTlVMTCwNCiAgICAgICAgICAgICAgICAgIG15X2xlZ2VuZCA9ICJyaWdodCIpDQoNCg0KcDExIDwtIG15Z2VvbV9iYXIobXlkYXRhID0gZGF0YV9yZWhvc3AsIA0KICAgICAgICAgICAgICAgICAgbXlleHBvc3VyZSA9ICJnZW5lcm8iLCANCiAgICAgICAgICAgICAgICAgIG15b3V0Y29tZSA9ICJyZWhvc3Bfb21zIiwgDQogICAgICAgICAgICAgICAgICBteXRpdGxlID0gIkfDqW5lcm8iLCANCiAgICAgICAgICAgICAgICAgIG15bGFiZWxfeCA9ICIiLCANCiAgICAgICAgICAgICAgICAgIG15bGFiZWxfeSA9ICJGcmVjdWVuY2lhIiwgDQogICAgICAgICAgICAgICAgICBteV9maWxsID0gIlJlaG9zcGl0YWxpemFjacOzbiIsIA0KICAgICAgICAgICAgICAgICAgbXlfYW5nbGUgPSBOVUxMLA0KICAgICAgICAgICAgICAgICAgbXlfbGVnZW5kID0gIm5vbmUiKQ0KDQpncmlkLmFycmFuZ2UocDE1LA0KICAgICAgICAgICAgIHAxMSwNCiAgICAgICAgICAgICBwMTYsDQogICAgICAgICAgICBuY29sID0gMiwNCiAgICAgICAgICAgIG5yb3cgPSAyLA0KICAgICAgICAgICAgbGF5b3V0X21hdHJpeCA9IHJiaW5kKGMoMSwyKSwgYygzLDMpKSkNCg0KYGBgDQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+Q29uIGVsIG9iamV0aXZvIGRlIGVucmlxdWVjZXIgZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3Jpbywgc2UgY2FsY3VsYXLDoW4gZG9zIG1lZGlkYXMgbXV5IGNvbcO6bmVzIGRlIGxhIHRlb3LDrWEgZGUgbGEgaW5mb3JtYWNpw7NuLCDDqXN0YXMgcGVybWl0ZW4gaW5mZXJpciBhbGdvIGRlbCBwb2RlciBwcmVkaWN0aXZvIHF1ZSBwdWVkZW4gdGVuZXIgbGFzIHZhcmlhYmxlcyBpbmRlcGVuZGllbnRlcywgYW50ZXMgZGUgaGFjZXIgcGFydGUgZGUgdW4gbW9kZWxvLjwvcD4NCg0KPGEgaHJlZj0iI0luaWNpbyI+Vm9sdmVyIGFsIGluaWNpbzwvYT48L2xpPg0KDQoNCg0KPGgyIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48YSBpZD0iQW5hbGlzaXNXT0UiPkFuw6FsaXNpcyBkZSBjbGFzaWZpY2FjacOzbiBiaW5hcmlhIHVzYW5kbyBXT0UgeSBlbCBJVjwvYT48L2gyPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkVsIHBlc28gZGUgbGEgZXZpZGVuY2lhIChXT0UpIHkgZWwgdmFsb3IgZGUgbGEgaW5mb3JtYWNpw7NuIChJVikgYXl1ZGFuLCBlbnRyZSBvdHJhcyBjb3NhcywgYSBkZXRlcm1pbmFyIGxhIGNvbnRyaWJ1Y2nDs24gaW5kZXBlbmRpZW50ZSBkZSBjYWRhIHZhcmlhYmxlIGFsIHJlc3VsdGFkbywgeSBkZXRlY3RhciByZWxhY2lvbmVzIGxpbmVhbGVzIHkgbm8gbGluZWFsZXMuIEVsIFdPRSBtaWRlIGxhIHJlbGFjacOzbiBlbnRyZSBsYSB2YXJpYWJsZSBwcmVkaWN0aXZhIHkgZWwgb2JqZXRvIGJpbmFyaW8sIG1pZW50cmFzIHF1ZSBlbCBJViBtaWRlIGxhIGZ1ZXJ6YSBwcmVkaWN0aXZhIGRlIGVzYSByZWxhY2nDs24uPC9wPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkxhIHRhYmxhIGEgY29udGludWFjacOzbiBjb250aWVuZSBsb3MgdmFsb3JlcyBkZWwgInZhbG9yIGRlIGxhIGluZm9ybWFjacOzbiIgY29uIHkgc2luIGVsIGFqdXN0ZSBkZXJpdmFkbyBkZSBsYSB2YWxpZGFjacOzbiBjcnV6YWRhLiBDdWFuZG8gc2UgcmVhbGl6YSBlbCBhanVzdGUgY29uIGVsIG9iamV0aXZvIGRlIHF1ZSBsb3MgcmVzdWx0YWRvcyBzZWFuIG3DoXMgZXN0YWJsZXMsIHPDs2xvIGVsIHBhZ28gZGVsIGRpYWduw7NzdGljbywgc2kgZWwgcGFjaWVudGUgcGFzw7MgcG9yIGxhIFVuaWRhZCBkZSBjdWlkYWRvcyBFc3BlY2lhbGVzIGxhIHByaW1lcmEgdmV6IHkgc2kgZnVlcm9uIHJlYWxpemFkb3MgcHJvY2VkaW1pZW50b3MgcXVpcsO6cmdpY29zIHNlcsOhbiBsYXMgw7puaWNhcyB2YXJpYWJsZXMgY29uIHN1ZmljaWVudGUgY2FwYWNpZGFkIGRlIHByZWRpY2Npw7NuIGEgbml2ZWwgaW5kaXZpZHVhbCB5IHVuaXZhcmlhYmxlIChJdiA+IDUlKS4gQ3VhbmRvIHNlIHJlbGFqYSBlbCBzdXB1ZXN0bywgSVYgc2luIHJlc3RhciBlbCBwZW5hbHR5LCBzZSBpbmNsdWlyw61hbiBsYXMgbWFyY2FzIHkgbGEgZWRhZCB5IGxhIGNpdWRhZC48L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0KZGF0YV9yZWhvc3AgPC0gZGF0YV9yZWhvc3AgJT4lDQogIG11dGF0ZShpZCA9IDE6bnJvdyguKSkgDQoNCmRhdGFfcmVob3NwICU+JQ0KICBzYW1wbGVfZnJhYyhzaXplID0gLjcwKSAtPiB0cmFpbg0KDQpkYXRhX3JlaG9zcCAlPiUNCiAgYW50aV9qb2luKHggPSAuLA0KICAgICAgICAgICAgeSA9IHRyYWluLCANCiAgICAgICAgICAgIGJ5ID0gImlkIikgLT4gdGVzdA0KICANCnRyYWluIDwtIHNlbGVjdCguZGF0YSA9IHRyYWluLCAtaWQpDQp0ZXN0IDwtIHNlbGVjdCguZGF0YSA9IHRlc3QsIC1pZCkNCg0KSVYgPC0gY3JlYXRlX2luZm90YWJsZXMoZGF0YSA9IHRyYWluLA0KICAgICAgICAgICAgICAgICAgIHZhbGlkID0gdGVzdCwNCiAgICAgICAgICAgICAgICAgICB5ID0gInJlaG9zcF9vbXMiKQ0KDQprYWJsZV9zdHlsaW5nKGthYmxlKElWJFN1bW1hcnkpLCANCiAgICAgICAgICAgICAgcG9zaXRpb24gPSAiY2VudGVyIiwgDQogICAgICAgICAgICAgIHJvd19sYWJlbF9wb3NpdGlvbiA9IDEsDQogICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGKQ0KYGBgDQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+RGUgYWN1ZXJkbyBhbCBwb2RlciBwcmVkaWN0aXZvIGRlIGNhZGEgdW5hIGRlIGxhcyB2YXJpYWJsZXMsIHNlIGVsaWdlbiBhcXVlbGxhcyBjdXlvIFZhbG9yIGRlIGxhIGluZm9ybWFjacOTbiAoSVYpIHNlYSBzdXBlcmlvciBhbCAyJSAoMCwwMikuIExhcyB2YXJpYWJsZXMgY29uIElWIGluZmVyaW9yZXMgYSBlc3RlIHZhbG9yIHNlIGNvbnNpZGVyYW4gaW1wcmVkaWN0aXZhcyB5IHNlIGRlY2lkZSBkZXNjYXJ0YXJsYXMuIExhcyB2YXJpYWJsZXMgcXVlIGNvbnRpbnVhbiwgZW4gb3JkZW4gZGUgcmVsZXZhbmNpYSBzZWd1biBzdSBwb2RlciBwcmVkaWN0b3IsIHNvbjo8L3A+DQoNCjx1bD4NCjxsaT5wYWdvX2hvc3A8L2xpPg0KPGxpPnF1aXJ1cjwvbGk+DQo8bGk+ZGlhc191Y2U8L2xpPg0KPGxpPmRpYXNfdWNpPC9saT4NCjxsaT5wcm92ZWVkb3I8L2xpPg0KPGxpPmRpYXNfaG9zcDwvbGk+DQo8bGk+ZXN0cmF0bzwvbGk+DQo8bGk+Y2l1ZGFkPC9saT4NCjwvdWw+DQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+RW5mb2NhbmRvbm9zIGVuIGVsIHBhZ28gZGVsIGRpYWduw7NzdGljbywgZWwgY3VhbCwgZXMgbGEgdmFyaWFibGUgY29uIG1heW9yIGluZmx1ZW5jaWEsIGVsIFdPRSBub3MgaW5kaWNhIHVuYSByZWxhY2nDs24gbm8gbGluZWFsLCBjb24gdW4gaW5jcmVtZW50byBlbiBlbCBXT0UgYSBtZWRpZGEgcXVlIGRpc21pbnV5ZSBlbCByYW5nbyBkZSBwYWdvIGVuIGVsIGRpYWduw7NzdGljby48L3A+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBldmFsID1UUlVFfQ0Ka2FibGVfc3R5bGluZyhrYWJsZShJViRUYWJsZXMkZWRhZCksIA0KICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJjZW50ZXIiLCANCiAgICAgICAgICAgICAgcm93X2xhYmVsX3Bvc2l0aW9uID0gMSwNCiAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBlY2hvID0gRkFMU0UsIGV2YWwgPVRSVUV9DQpuIDwtIG5hbWVzKElWJFRhYmxlcykNCmZvciAoaSBpbiAxOmxlbmd0aChuKSl7DQogICBwbG90X2luZm90YWJsZXMoSVYsIG5baV0pfQ0KDQpNdWx0aVBsb3QoSVYsIElWJFN1bW1hcnkkVmFyaWFibGVbMTo5XSkNCmBgYA0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkNvbW8gc2UgcHVkbyBvYnNlcnZhciBlbiBlbCBhbmFsaXNpcyBkZWwgV09FLCBlc3RhIHTDqWNuaWNhIGFqdXN0YSBsb3MgdmFsb3JlcyBkZSBsYXMgdmFyaWFibGVzIG51bWVyaWNhcyBlbiByYW5nb3MgYWNvdGFkb3MgZGUgYWN1ZXJkbyBhbCB2YWxvciBkZSBsYSBpbmZvcm1hY2lvbiBkZSBjYWRhIHVuYSBkZSBlbGxhcyBlbiByZWxhY2lvbiBjb24gbGEgdmFyaWFibGUgZGVwZW5kaWVudGUuIFBvciBlc3RvLCBlcyBpbXBvcnRhbnRlIHRyYW5zZm9ybWFyIGRpY2hhcyB2YXJpYWJsZXMgZW4gbG9zIHJhbmdvcyByZWNvbWVuZGFkb3MuPC9wPg0KDQpgYGB7cn0NCiMgZGF0YV9yZWhvc3AgJT4lDQojICAgbXV0YXRlKHBhZ29faG9zcDEgPSBjYXNlX3doZW4oIHBhZ29faG9zcCA8PSAxMDc0MTAgfiAiWzAsMTA3NDEwXSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ29faG9zcCA+PSAxMDc1NzAgJiBwYWdvX2hvc3AgPD0gNzc2OTY1IH4gIlsxMDc1NzAsNzc2OTY1XSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ29faG9zcCA+PSA3Nzc2OTcgJiBwYWdvX2hvc3AgPD0gMTU0NzgwNiB+ICJbNzc3Njk3LDE1NDc4MDZdIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFnb19ob3NwID49IDE1NDc4NDcgJiBwYWdvX2hvc3AgPD0gMjI1MTc2NCB+ICJbMTU0Nzg0NywyMjUxNzY0XSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ29faG9zcCA+PSAyMjUxOTEzICYgcGFnb19ob3NwIDw9IDMwMjE4NjIgfiAiWzIyNTE5MTMsMzAyMTg2Ml0iLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdvX2hvc3AgPj0gMzAyMjAzMCAmIHBhZ29faG9zcCA8PSAzOTk2OTI4IH4gIlszMDIyMDMwLDM5OTY5MjhdIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFnb19ob3NwID49IDM5OTY5MzMgJiBwYWdvX2hvc3AgPD0gNTMyODQyMyB+ICJbMzk5NjkzMyw1MzI4NDIzXSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ29faG9zcCA+PSA1MzI5NTAwICYgcGFnb19ob3NwIDw9IDcwNDgyOTAgfiAiWzUzMjk1MDAsNzA0ODI5MF0iLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdvX2hvc3AgPj0gNzA0ODkwMiAmIHBhZ29faG9zcCA8PSAxMTQwODQxNSB+ICJbNzA0ODkwMiwxMTQwODQxNV0iLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdvX2hvc3AgPj0gMTE0MDg2MjUgJiBwYWdvX2hvc3AgPD0gNDczODc4ODMgfiAiWzExNDA4NjI1LDQ3Mzg3ODgzXSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ29faG9zcCA+PSA0NzM4Nzg4MyB+ICJbNDczODc4ODMrIiksDQojICAgICAgICAgIGRpYXNfaG9zcDEgPSBjYXNlX3doZW4oIGRpYXNfaG9zcCA9IDEgfiAiWzFdIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWFzX2hvc3AgPSAyIH4gIlsyXSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlhc19ob3NwID0gMyB+ICJbM10iLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpYXNfaG9zcCA9IDQgfiAiWzRdIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWFzX2hvc3AgPj0gNSAmIGRpYXNfaG9zcCA8PSA3IH4gIls1LDddIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWFzX2hvc3AgPj0gOCAmIGRpYXNfaG9zcCA8PSAzMCB+ICJbOCwzMF0iKSkgLT4gZGF0YV9yZWhvc3AyDQojIA0KIyANCiMgc3RyKGRhdGFfcmVob3NwKQ0KDQpgYGANCg0KPGEgaHJlZj0iI0luaWNpbyI+Vm9sdmVyIGFsIGluaWNpbzwvYT48L2xpPg0KDQoNCjxoMiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PGEgaWQ9Ik1vZGVsbyI+TW9kZWxvPC9hPjwvaDI+DQoNClNlbGVjY2lvbiBkZSB2YXJpYWJsZXMgcGFyYSBlbCBtb2RlbG8NCmBgYHtyfQ0KZGF0YV9yZWhvc3AgJT4lDQogIHNlbGVjdChpZCwNCiAgICAgICAgcGFnb19ob3NwLA0KICAgICAgICBxdWlydXIsDQogICAgICAgIGRpYXNfdWNlLA0KICAgICAgICBkaWFzX3VjaSwNCiAgICAgICAgcHJvdmVlZG9yLA0KICAgICAgICBkaWFzX2hvc3AsDQogICAgICAgIGVzdHJhdG8sDQogICAgICAgIGNpdWRhZCwNCiAgICAgICAgcmVob3NwX29tcykgLT4gZGF0YV9yZWhvc3ANCg0KZGF0YV9yZWhvc3AgJT4lDQogIHNhbXBsZV9mcmFjKHNpemUgPSAwLjcpIC0+IHRyYWluaW5nDQoNCmRhdGFfcmVob3NwICU+JQ0KICBhbnRpX2pvaW4oeCA9IC4sDQogICAgICAgICAgICB5ID0gdHJhaW5pbmcsDQogICAgICAgICAgICBieSA9ICJpZCIpIC0+IHRlc3RpbmcNCg0KdGVzdGluZyAlPiUNCiAgc2VsZWN0KC1pZCkgLT4gdGVzdGluZw0KDQp0cmFpbmluZyAlPiUNCiAgc2VsZWN0KC1pZCkgJT4lDQogIG11dGF0ZShyZWhvc3Bfb21zID0gYXMuZmFjdG9yKHJlaG9zcF9vbXMpKSAtPiB0cmFpbmluZw0KDQpgYGANCg0KDQoNCjxoMyBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PGEgaWQ9IlNNT1RFIj5TTU9URTwvYT48L2gzPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPkNvbW8gc2UgaGFiaWEgbWVuY2lvbmFkbyBhbnRlcmlvcm1lbnRlLCBsYSBpbmZvcm1hY2lvbiBzZSBlbmN1ZW50cmEgZGVzYmFsYW5jZWFkYTsgZXN0byBlcywgdGVuaWVuZG8gZW4gY3VlbnRhIHF1ZSBlbCBwcm9ibGVtYSBlbiBxdWUgc2UgZXN0YSB0cmFiYWphbmRvIGNvbnNpc3RlIGVuIGxhIGNsYXNpZmljYWNpb24gZGUgdW5hIHZhcmlhYmxlIGJpbmFyaWEsIHNlIGRlYmUgYW5hbGl6YXIgZWwgbml2ZWwgZGUgcmVwcmVzZW50YWNpb24gZGUgbG9zIHBvc2libGVzIHZhbG9yZXMgZGUgbGEgdmFyaWFibGUgYmluYXJpYSBkZW50cm8gZGVsIGNvbmp1bnRvIGRlIGluZm9ybWFjaW9uLjwvcD4NCg0KDQpgYGB7cn0NCiN2ZXJpZmljYXIgY2xhc2UgYmFsYW5jZWFkYQ0KcHJvcC50YWJsZSh0YWJsZShkYXRhX3JlaG9zcCRyZWhvc3Bfb21zKSkNCmBgYA0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPlZlbW9zIHF1ZSBsYSByZXByZXNlbnRhY2lvbiBwYXJhIGxhIGNhdGVnb3LDrWEgcG9zaXRpdmEgZXMgdW4gcG9jbyBtYXMgZGVsIDIlIGRlIGxhIGluZm9ybWFjacOzbi4gRW4gZXN0ZSBjYXNvIHZhbW9zIGEgcmVhbGl6YXIgdW4gdHJhdGFtaWVudG8gZGUgbGEgaW5mb3JtYWNpw7NuIHF1ZSBwZXJtaXRhIGF1bWVudGFyIGxhIGNsYXNlIG1pbm9yaXRhcmlhLCBzaW4gdXRpbGl6YXIgc29sdWNpb25lcyBnZW7DqXJpY2FzIGNvbW8gcmVkdWNpciBsYSBjbGFzZSBtYXlvcml0YXJpYSBhbCBuaXZlbCBkZSBsYSBjbGFzZSBtaW5vcml0YXJpYS48L3A+DQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+UGFyYSBlc3RlIGNhc28gdmFtb3MgYSB1dGlsaXphciBsYSB0w6ljbmljYSBTTU9URSAoU3ludGhldGljIE1pbm9yaXR5IE92ZXJzYW1wbGluZyBNZXRob2QpLCBsYSBjdWFsIGdlbmVyYSBudWV2YXMgaW5zdGFuY2lhcyBhcnRpZmljaWFsZXMgZGUgbGEgY2xhc2UgbWlub3JpdGFyaWEgaW50ZXJwb2xhbmRvIGxvcyB2YWxvcmVzIGRlIGxhcyBpbnN0YW5jaWFzIG1pbm9yaXRhcmlhcyBtw6FzIGNlcmNhbmFzIGEgdW5hIGRhZGEuPC9wPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPlBvciBtZWRpbyBkZSBTTU9URSBzZSBnZW5lcmFyw6EgdW4gbnVldm8gc2V0IGRlIGRhdG9zIGRlIGVudHJlbmFtaWVudG8sIGVuIGVsIGN1YWwgc2UgdGVuZ2EgdW4gNjAlIGRlIGluZm9ybWFjaW9uIHBhcmEgbGEgY2F0ZWdvcmlhIG5lZ2F0aXZhIChyZWhvc3Bfb21zID0gMCkgeSA0MCUgcGFyYSBsYSBjYXRlZ29yaWEgcG9zaXRpdmEgKHJlaG9zcF9vbXMgPSAwKS48L3A+DQoNCg0KYGBge3J9DQp0cmFpbmluZyA8LSBTTU9URShyZWhvc3Bfb21zIH4gLiwgYXMuZGF0YS5mcmFtZSh0cmFpbmluZyksIHBlcmMub3ZlciA9IDMwMCwgcGVyYy51bmRlciA9IDIwMCkNCmBgYA0KDQpWZXJpZmljYW1vcyBxdWUgZWwgc2V0IGRlIGVudHJlbmFtaWVudG8gc2UgZW5jdWVudHJlIGJhbGFuY2VhZG8NCg0KYGBge3J9DQpwcm9wLnRhYmxlKHRhYmxlKHRyYWluaW5nJHJlaG9zcF9vbXMpKQ0KYGBgDQoNCkVzdGltYW5kbyBlbCBtb2RlbG8NCmBgYHtyfQ0KbXlsb2dpdCA8LSBnbG0ocmVob3NwX29tcyB+IHBhZ29faG9zcCArIHF1aXJ1ciArICBkaWFzX2hvc3AgKyBkaWFzX3VjZSArIGRpYXNfdWNpICsgZXN0cmF0bywgZGF0YSA9IHRyYWluaW5nLCBmYW1pbHkgPSAiYmlub21pYWwiKQ0KDQpzdW1tYXJ5KG15bG9naXQpDQpgYGANCg0KYGBge3J9DQpwcmVkIDwtIHByZWRpY3QobXlsb2dpdCwgbmV3ZGF0YSA9IHRyYWluaW5nWy05XSwgdHlwZSA9ICJyZXNwb25zZSIpDQogDQp5X3ByZWRfbnVtX3RyYWluIDwtIGlmZWxzZShwcmVkID4gMC41LCAxLCAwKQ0KeV9wcmVkX3RyYWluIDwtIGZhY3Rvcih5X3ByZWRfbnVtLCBsZXZlbHM9YygwLCAxKSkNCnlfYWN0X3RyYWluIDwtIHRyYWluaW5nJHJlaG9zcF9vbXMNCiANCm1lYW4oeV9wcmVkX3RyYWluID09IHlfYWN0X3RyYWluKSAgDQpgYGANCg0KDQpQcmVkaWNpZW5kbyB5IGV2YWx1YW5kbyBwZXJmb3JtYW5jZQ0KYGBge3J9DQpwcm9iX3ByZWQgPSBwcmVkaWN0KG15bG9naXQsIHR5cGUgPSAncmVzcG9uc2UnLCBuZXdkYXRhID0gdGVzdGluZ1stOV0pDQp5X3ByZWQgPSBpZmVsc2UocHJvYl9wcmVkID4gMC41LCAxLCAwKQ0KeV9wcmVkX2ZhYyA8LSBmYWN0b3IoeV9wcmVkLCBsZXZlbHM9YygwLCAxKSkNCnlfYWN0IDwtIHRlc3RpbmckcmVob3NwX29tcw0KIA0KbWVhbih5X3ByZWQgPT0geV9hY3QpICAjIFglDQogDQpgYGANCg0KYGBge3J9DQoNCmxpYnJhcnkoUk9DUikNClJPQ1JwcmVkID0gcHJlZGljdGlvbihwcm9iX3ByZWQsIHRlc3RpbmckcmVob3NwX29tcykNCiANCiMgUGVyZm9ybWFuY2UgZnVuY3Rpb24NClJPQ1JwZXJmID0gcGVyZm9ybWFuY2UoUk9DUnByZWQsICJ0cHIiLCAiZnByIikNCg0KcGVyZjEgPC0gcGVyZm9ybWFuY2UoUk9DUnByZWQsICJwcmVjIiwgInJlYyIpDQpwbG90KHBlcmYxKQ0KIA0KIyBQbG90IFJPQyBjdXJ2ZQ0KcGxvdChST0NScGVyZikNCiMgQWRkIGNvbG9ycw0KcGxvdChST0NScGVyZiwgY29sb3JpemU9VFJVRSkNCiMgQWRkIHRocmVzaG9sZCBsYWJlbHMgDQpwbG90KFJPQ1JwZXJmLCBjb2xvcml6ZT1UUlVFLCBwcmludC5jdXRvZmZzLmF0PXNlcSgwLDEsYnk9MC4xKSwgdGV4dC5hZGo9YygtMC4yLDEuNykpDQoNCg0KcHJvYl9wcmVkID0gcHJlZGljdChteWxvZ2l0LCB0eXBlID0gJ3Jlc3BvbnNlJywgbmV3ZGF0YSA9IHRlc3RpbmdbLTldKQ0KeV9wcmVkID0gaWZlbHNlKHByb2JfcHJlZCA+IDAuNSwgMSwgMCkNCmNtID0gdGFibGUoYXMubWF0cml4KHRlc3RpbmdbLCA5XSksIHlfcHJlZCA+IDAuNSkNCg0KYGBgDQoNCg==